You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kg...@apache.org on 2018/06/01 15:00:13 UTC

[03/11] qpid-dispatch git commit: DISPATCH-965: port python code to Python 3. Stay compatible with 2.6-7

DISPATCH-965: port python code to Python 3. Stay compatible with 2.6-7


Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/878534ec
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/878534ec
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/878534ec

Branch: refs/heads/master
Commit: 878534ec682b13cc731197318c8e6f32f06d6216
Parents: 4bd79a3
Author: Kenneth Giusti <kg...@redhat.com>
Authored: Wed Apr 11 17:24:23 2018 -0400
Committer: Kenneth Giusti <kg...@redhat.com>
Committed: Thu May 10 02:39:02 2018 -0400

----------------------------------------------------------------------
 .gitignore                                      |   1 +
 console/config/config.py                        |  34 +--
 console/config/mock/section.py                  |  10 +-
 doc/man/help2txt.py                             |  12 +-
 doc/man/qdrouterd.conf.5.py                     |   6 +-
 python/qpid_dispatch/management/entity.py       |  40 ++-
 .../qpid_dispatch_internal/compat/__init__.py   | 102 +++++++-
 .../compat/ordereddict.py                       |   6 +-
 python/qpid_dispatch_internal/dispatch.py       |  15 +-
 .../qpid_dispatch_internal/management/agent.py  |  69 +++--
 .../qpid_dispatch_internal/management/config.py |  15 +-
 .../management/qdrouter.py                      |   4 +-
 .../qpid_dispatch_internal/management/schema.py |  73 +++---
 .../management/schema_doc.py                    |  11 +-
 .../policy/policy_local.py                      |  50 ++--
 .../policy/policy_manager.py                    |   3 +-
 .../policy/policy_util.py                       |   6 +-
 .../qpid_dispatch_internal/router/__init__.py   |   2 +-
 python/qpid_dispatch_internal/router/data.py    |  53 ++--
 python/qpid_dispatch_internal/router/engine.py  |  24 +-
 python/qpid_dispatch_internal/router/hello.py   |  11 +-
 python/qpid_dispatch_internal/router/link.py    |   2 +-
 python/qpid_dispatch_internal/router/mobile.py  |   2 +-
 python/qpid_dispatch_internal/router/node.py    |  30 ++-
 python/qpid_dispatch_internal/router/path.py    |  14 +-
 python/qpid_dispatch_internal/tools/command.py  |  11 +-
 python/qpid_dispatch_internal/tools/display.py  |  32 +--
 run.py.in                                       |  13 +-
 src/CMakeLists.txt                              |   1 +
 src/entity.c                                    |  29 +--
 src/error.c                                     |  46 ++--
 src/log.c                                       |  11 +-
 src/parse.c                                     | 141 +++++++----
 src/policy.c                                    |  62 +++--
 src/python_embedded.c                           | 251 ++++++++++---------
 src/python_private.h                            |  46 ++++
 src/python_utils.c                              |  68 +++++
 src/router_core/agent_config_address.c          |   4 +-
 src/router_core/agent_config_auto_link.c        |   2 +-
 src/router_core/agent_connection.c              |   3 +
 src/router_core/exchange_bindings.c             |  10 +-
 src/router_core/management_agent.c              |   4 +-
 src/router_pynode.c                             |  77 ++----
 src/schema_c.py                                 |   4 +-
 src/server.c                                    |   7 +-
 tests/CMakeLists.txt                            |  23 ++
 tests/management/__init__.py                    |   7 +-
 tests/mock/dispatch.py                          |   6 +-
 tests/router_engine_test.py                     |  18 +-
 tests/router_policy_test.py                     |   2 +
 tests/system_test.py                            |  38 ++-
 tests/system_tests_auth_service_plugin.py       |   4 +-
 tests/system_tests_authz_service_plugin.py      |   4 +-
 tests/system_tests_autolinks.py                 |  10 +-
 tests/system_tests_bad_configuration.py         |   5 +-
 tests/system_tests_broker.py                    |   4 +-
 tests/system_tests_cmdline_parsing.py           |   6 +-
 tests/system_tests_default_distribution.py      |   3 +-
 tests/system_tests_delivery_abort.py            |   9 +-
 tests/system_tests_deprecated.py                |   4 +-
 ..._tests_disallow_link_resumable_link_route.py |   9 +-
 tests/system_tests_distribution.py              |  68 ++---
 tests/system_tests_exchange_bindings.py         |   5 +-
 tests/system_tests_handle_failover.py           |  10 +-
 tests/system_tests_http.py                      |   2 +-
 tests/system_tests_link_routes.py               |  16 +-
 tests/system_tests_log_message_components.py    |  10 +-
 tests/system_tests_management.py                |  12 +-
 tests/system_tests_multi_tenancy.py             |   4 +-
 tests/system_tests_one_router.py                |  26 +-
 tests/system_tests_policy.py                    |  40 +--
 tests/system_tests_protocol_settings.py         |   3 +-
 tests/system_tests_qdmanage.py                  |  15 +-
 tests/system_tests_qdstat.py                    |  22 +-
 tests/system_tests_sasl_plain.py                |  14 +-
 tests/system_tests_topology.py                  |   3 +-
 tests/system_tests_topology_addition.py         |  12 +-
 tests/system_tests_topology_disposition.py      |  49 ++--
 tests/system_tests_user_id_proxy.py             |   5 +-
 tools/qdmanage                                  |  18 +-
 tools/qdstat                                    |  11 +-
 tox.ini                                         |  33 +++
 82 files changed, 1178 insertions(+), 769 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index b4164bb..52d844c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,4 @@ tests/policy-1/policy-*.json
 .settings
 console/test/topolgies/config-*
 .history
+.tox

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/console/config/config.py
----------------------------------------------------------------------
diff --git a/console/config/config.py b/console/config/config.py
index f83057e..ae51bd7 100755
--- a/console/config/config.py
+++ b/console/config/config.py
@@ -34,6 +34,11 @@ import threading
 import subprocess
 from distutils.spawn import find_executable
 
+# Python 3 does not have a unicode() builtin method
+if sys.version_info[0] > 2:
+    def unicode(x, encoding='utf-8', errors=None):
+        return str(x, encoding, errors)
+
 get_class = lambda x: globals()[x]
 sectionKeys = {"log": "module", "sslProfile": "name", "connector": "port", "listener": "port", "address": "prefix|pattern"}
 
@@ -87,7 +92,7 @@ class DirectoryConfigs(object):
         try:
             c = get_class(cname)
             return c(**s[1])
-        except KeyError, e:
+        except KeyError:
             return None
 
 class Manager(object):
@@ -104,15 +109,15 @@ class Manager(object):
         try:
             method = getattr(self, m)
         except AttributeError:
-            print op + " is not implemented yet"
+            print(op + " is not implemented yet")
             return None
         if self.verbose:
-            print "Got request " + op
+            print("Got request " + op)
         return method(request)
 
     def ANSIBLE_INSTALLED(self, request):
         if self.verbose:
-            print "Ansible is", "installed" if find_executable("ansible") else "not installed"
+            print("Ansible is %s" % "installed" if find_executable("ansible") else "not installed")
         return "installed" if find_executable("ansible") else ""
 
     # if the node has listeners, and one of them has an http:'true'
@@ -176,7 +181,7 @@ class Manager(object):
         def ansible_done(returncode):
             os.remove(inventory_file)
             if self.verbose:
-                print "-------------- DEPLOYMENT DONE with return code", returncode, "------------"
+                print("-------------- DEPLOYMENT DONE with return code", returncode, "------------")
             if returncode:
                 self.state = returncode
             else:
@@ -261,7 +266,7 @@ class Manager(object):
 
     def GET_TOPOLOGY(self, request):
         if self.verbose:
-            pprint (self.topology)
+            pprint(self.topology)
         return unicode(self.topology)
 
     def GET_TOPOLOGY_LIST(self, request):
@@ -327,7 +332,7 @@ class Manager(object):
             # remove all .conf files from the output dir. they will be recreated below possibly under new names
             for f in glob(self.topo_base + topology + "/*.conf"):
                 if self.verbose:
-                    print "Removing", f
+                    print("Removing %s" % f)
                 os.remove(f)
 
         # establish connections and listeners for each node based on links
@@ -337,7 +342,8 @@ class Manager(object):
         for node in nodes:
             if node['nodeType'] == 'inter-router':
                 if self.verbose:
-                    print "------------- processing node", node["name"], "---------------"
+                    print("------------- processing node %s "
+                          "---------------" % node["name"])
 
                 nname = node["name"]
                 if nodeIndex is not None:
@@ -360,14 +366,14 @@ class Manager(object):
                 for sectionKey in sectionKeys:
                     if sectionKey+'s' in node:
                         if self.verbose:
-                            print "found", sectionKey+'s'
+                            print("found %s" % sectionKey+'s')
                         for k in node[sectionKey+'s']:
                             if self.verbose:
-                                print "processing", k
+                                print("processing %s" % k)
                             o = node[sectionKey+'s'][k]
                             cname = sectionKey[0].upper() + sectionKey[1:] + "Section"
                             if self.verbose:
-                                print "class name is", cname
+                                print("class name is %s" % cname)
                             c = get_class(cname)
                             if sectionKey == "listener" and o['port'] != 'amqp' and int(o['port']) == http_port:
                                 config_fp.write("\n# Listener for a console\n")
@@ -376,7 +382,7 @@ class Manager(object):
                             if node.get('host') == o.get('host'):
                                 o['host'] = '0.0.0.0'
                             if self.verbose:
-                                print "attributes", o, "is written as", str(c(**o))
+                                print("attributes %s is written as %s" % (o, str(c(**o))))
                             config_fp.write(str(c(**o)) + "\n")
 
                 if 'listener' in node:
@@ -450,7 +456,7 @@ args = parser.parse_args()
 
 try:
     httpd = ConfigTCPServer(args.port, Manager(args.topology, args.verbose), args.verbose)
-    print "serving at port", args.port
+    print("serving at port %s" % args.port)
     httpd.serve_forever()
 except KeyboardInterrupt:
-    pass
\ No newline at end of file
+    pass

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/console/config/mock/section.py
----------------------------------------------------------------------
diff --git a/console/config/mock/section.py b/console/config/mock/section.py
index ce71d7c..ac5b154 100644
--- a/console/config/mock/section.py
+++ b/console/config/mock/section.py
@@ -103,9 +103,9 @@ if __name__ == '__main__':
     c = ConnectorSection(20001)
     s = SslProfileSection()
     g = LogSection(module="ROUTER", enable="trace+")
-    print r
-    print l
-    print c
-    print s
-    print g
+    print(r)
+    print(l)
+    print(c)
+    print(s)
+    print(g)
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/doc/man/help2txt.py
----------------------------------------------------------------------
diff --git a/doc/man/help2txt.py b/doc/man/help2txt.py
index a1eca2c..0fb2f7f 100644
--- a/doc/man/help2txt.py
+++ b/doc/man/help2txt.py
@@ -22,8 +22,9 @@ Convert --help output of a program into asciidoc text format.
 """
 from __future__ import print_function
 import re, sys
-from qpid_dispatch_internal.compat.subproc import check_output, STDOUT, CalledProcessError
-from os import path
+from qpid_dispatch_internal.compat import PY_STRING_TYPE
+from qpid_dispatch_internal.compat.subproc import check_output
+
 
 def help2txt(help_out):
     VALUE = r"(?:[\w-]+|<[^>]+>)"
@@ -34,6 +35,10 @@ def help2txt(help_out):
     OPT_HELP = r"^\s+(%s)(%s)" % (OPTIONS, HELP)
     SUBHEAD = r"^((?: +\w+)*):$"
 
+    # check_output returns binary in py3
+    if not isinstance(help_out, PY_STRING_TYPE):
+        help_out = help_out.decode()
+
     options = re.search("^Options:$", help_out, re.IGNORECASE | re.MULTILINE)
     if (options): help_out = help_out[options.end():]
     result = ""
@@ -49,7 +54,8 @@ def help2txt(help_out):
     return result
 
 def main(argv):
-    if len(argv) < 2: raise ValueError("Wrong number of arguments: "+usage)
+    if len(argv) < 2: raise ValueError("Wrong number of arguments\nUsage %s"
+                                       " <program> [args,...]" % argv[0])
     program = argv[1:]
     print(help2txt(check_output(program)))
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/doc/man/qdrouterd.conf.5.py
----------------------------------------------------------------------
diff --git a/doc/man/qdrouterd.conf.5.py b/doc/man/qdrouterd.conf.5.py
index 9c467b3..efdb554 100644
--- a/doc/man/qdrouterd.conf.5.py
+++ b/doc/man/qdrouterd.conf.5.py
@@ -24,9 +24,7 @@ Generate the qdrouterd.conf. man page from the qdrouterd management schema.
 import sys
 from qpid_dispatch_internal.management.qdrouter import QdSchema
 from qpid_dispatch_internal.management.schema_doc import SchemaWriter
-from qpid_dispatch_internal.management.schema import AttributeType
-
-from qpid_dispatch_internal.compat import OrderedDict
+from qpid_dispatch_internal.compat import dict_itervalues
 
 CONNECTOR = 'org.apache.qpid.dispatch.connector'
 LISTENER = 'org.apache.qpid.dispatch.listener'
@@ -132,7 +130,7 @@ listener {
         with self.section("Configuration Sections"):
 
             config = self.schema.entity_type("configurationEntity")
-            for entity_type in self.schema.entity_types.itervalues():
+            for entity_type in dict_itervalues(self.schema.entity_types):
                 if config in entity_type.all_bases:
                     with self.section(entity_type.short_name):
                         if entity_type.description:

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch/management/entity.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch/management/entity.py b/python/qpid_dispatch/management/entity.py
index 4e5466a..19df0e8 100644
--- a/python/qpid_dispatch/management/entity.py
+++ b/python/qpid_dispatch/management/entity.py
@@ -22,14 +22,30 @@ AMQP Managment Entity
 """
 
 import itertools, re
+import sys
+
+
+if sys.version_info[0] > 2:
+    # Python 3 does not have a unicode() builtin method,
+    # luckily all strings are unicode to start with
+    def unicode(s):
+        return s
+    def dict_iteritems(d):
+        return iter(d.items())
+else:
+    def dict_iteritems(d):
+        return d.iteritems()
+
+
 
 def clean_dict(items, **kwargs):
     """
     @param items: A mapping or iterable of pairs.
     @return: dict containing items + kwargs without any None values. All keys are unicode.
     """
-    if hasattr(items, 'iteritems'): items = items.iteritems()
-    return dict((unicode(k), v) for k, v in itertools.chain(items, kwargs.iteritems())
+    if isinstance(items, dict): items = dict_iteritems(items)
+    return dict((unicode(k), v) for k, v in itertools.chain(items,
+                                                            dict_iteritems(kwargs))
                 if v is not None)
 
 class EntityBase(object):
@@ -50,10 +66,10 @@ class EntityBase(object):
     def __init__(self, attributes=None, **kwargs):
         self.__dict__['attributes'] = {}
         if attributes:
-            for k, v in attributes.iteritems():
+            for k, v in dict_iteritems(attributes):
                 self.attributes[k] = v
                 self.__dict__[self._pyname(k)] = v
-        for k, v in kwargs.iteritems():
+        for k, v in dict_iteritems(kwargs):
             self._set(k, v)
 
     def __getitem__(self, name):
@@ -88,22 +104,24 @@ class EntityBase(object):
 
     def __repr__(self): return "EntityBase(%r)" % self.attributes
 
-    SPECIAL = [u"name", u"identity", u"type"]
-    N_SPECIAL = len(SPECIAL)
-    PRIORITY = dict([(SPECIAL[i], i) for i in xrange(N_SPECIAL)])
+    # attributes name, identity and type are special snowflake
+    # attributes that we print before all the not so special
+    # attributes.  Assign each a priority for the sort
+    _SPECIAL = {u"name": 0, u"identity": 1, u"type": 2}
 
     def __str__(self):
-        # Print the name and identity first.
-        keys = sorted(self.attributes.keys(), key=lambda k: self.PRIORITY.get(k, self.N_SPECIAL))
+        # Sort so the _SPECIAL attributes are printed first, 3 ==
+        # lower priority than special
+        keys = sorted(self.attributes.keys(),
+                      key=lambda k: self._SPECIAL.get(k, 3))
         return "Entity(%s)" % ", ".join("%s=%s" % (k, self.attributes[k]) for k in keys)
 
-
 def update(entity, values):
     """Update entity from values
     @param entity: an Entity
     @param values: a map of values
     """
-    for k, v in values.iteritems(): entity[k] = v
+    for k, v in dict_iteritems(values): entity[k] = v
 
 SEPARATOR_RE = re.compile(r' |_|-|\.')
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/compat/__init__.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/compat/__init__.py b/python/qpid_dispatch_internal/compat/__init__.py
index 2a0988b..8af2d21 100644
--- a/python/qpid_dispatch_internal/compat/__init__.py
+++ b/python/qpid_dispatch_internal/compat/__init__.py
@@ -19,12 +19,28 @@
 
 """Compatibility hacks for older versions of python"""
 
-import sys
+__all__ = [
+    "OrderedDict",
+    "JSON_LOAD_KWARGS",
+    "dictify",
+    "IS_PY2",
+    "PY_STRING_TYPE",
+    "PY_TEXT_TYPE",
+    "PY_BINARY_TYPE",
+    "PY_INTEGER_TYPES",
+    "dict_iterkeys",
+    "dict_itervalues",
+    "dict_iteritems",
+    "UNICODE",
+    "BINARY"
+]
 
-__all__ = ["OrderedDict"]
+import sys
 
-try: from collections import OrderedDict
-except: from ordereddict import OrderedDict
+try:
+    from collections import OrderedDict
+except Exception:
+    from ordereddict import OrderedDict
 
 if sys.version_info >= (2, 7):
     JSON_LOAD_KWARGS = {'object_pairs_hook':OrderedDict}
@@ -34,6 +50,82 @@ else:
 def dictify(od):
     """Recursively replace OrderedDict with dict"""
     if isinstance(od, OrderedDict):
-        return dict((k, dictify(v)) for k, v in od.iteritems())
+        return dict((k, dictify(v)) for k, v in dict_iteritems(od))
     else:
         return od
+
+IS_PY2 = sys.version_info[0] == 2
+
+if IS_PY2:
+    PY_STRING_TYPE = basestring  # noqa: F821
+    PY_TEXT_TYPE = unicode  # noqa: F821
+    PY_BINARY_TYPE = str
+    PY_INTEGER_TYPES = (int, long)  # noqa: F821
+    PY_LONG_TYPE = long  # noqa: F821
+    def dict_iterkeys(d):
+        return d.iterkeys()
+    def dict_itervalues(d):
+        return d.itervalues()
+    def dict_iteritems(d):
+        return d.iteritems()
+    def dict_keys(d):
+        return d.keys()
+    def dict_values(d):
+        return d.values()
+    def dict_items(d):
+        return d.items()
+    def BINARY(s):
+        ts = type(s)
+        if ts is str:
+            return s
+        elif ts is unicode:  # noqa: F821
+            return s.encode("utf-8")
+        else:
+            raise TypeError("%s cannot be converted to binary" % ts)
+    def UNICODE(s):
+        if type(s) is str:
+            return s.decode("utf-8")
+        elif type(s) is unicode:  # noqa: F821
+            return s
+        else:
+            return unicode(str(s), "utf-8")  # noqa: F821
+    def LONG(i):
+        return long(i)  # noqa: F821
+else:
+    PY_STRING_TYPE = str
+    PY_TEXT_TYPE = str
+    PY_BINARY_TYPE = bytes
+    PY_INTEGER_TYPES = (int,)
+    PY_LONG_TYPE = int
+    def dict_iterkeys(d):
+        return iter(d.keys())
+    def dict_itervalues(d):
+        return iter(d.values())
+    def dict_iteritems(d):
+        return iter(d.items())
+    # .keys(), .items(), .values()
+    # now return a dict_view not a list. Should be ok unless dict is modified
+    # when iterating over it. Use these if that's the case:
+    def dict_keys(d):
+        return list(d.keys())
+    def dict_values(d):
+        return list(d.values())
+    def dict_items(d):
+        return list(d.items())
+    def BINARY(s):
+        st = type(s)
+        if st is str:
+            return s.encode("utf-8")
+        elif st is bytes:
+            return s
+        else:
+            raise TypeError("%s cannot be converted to binary" % st)
+    def UNICODE(s):
+        if type(s) is bytes:
+            return s.decode("utf-8")
+        elif type(s) is str:
+            return s
+        else:
+            return str(s)
+    def LONG(i):
+        return int(i)

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/compat/ordereddict.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/compat/ordereddict.py b/python/qpid_dispatch_internal/compat/ordereddict.py
index a312cfa..2fa007d 100644
--- a/python/qpid_dispatch_internal/compat/ordereddict.py
+++ b/python/qpid_dispatch_internal/compat/ordereddict.py
@@ -31,7 +31,11 @@ try:
 except ImportError:
     pass
 
-
+# Note well: this class is only used for versions of python < 2.7
+# Since 2.7 OrderDict is part of the collections module of the standard
+# library. It does not need to be python3 compatible and can
+# eventually removed when python versions <= 2.6 are no longer supported.
+#
 class OrderedDict(dict):
     'Dictionary that remembers insertion order'
     # An inherited dict maps keys to values.

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/dispatch.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/dispatch.py b/python/qpid_dispatch_internal/dispatch.py
index 4c9123b..a8cd05b 100644
--- a/python/qpid_dispatch_internal/dispatch.py
+++ b/python/qpid_dispatch_internal/dispatch.py
@@ -33,6 +33,7 @@ This module also prevents the proton python module from being accidentally loade
 import sys, ctypes
 from ctypes import c_char_p, c_long, py_object
 import qpid_dispatch_site
+from .compat import UNICODE
 
 class CError(Exception):
     """Exception raised if there is an error in a C call"""
@@ -54,7 +55,9 @@ class QdDll(ctypes.PyDLL):
         # No check on qd_error_* functions, it would be recursive
         self._prototype(self.qd_error_code, c_long, [], check=False)
         self._prototype(self.qd_error_message, c_char_p, [], check=False)
-
+        # in python3 c_char_p returns a byte type for the error message.  We
+        # need to convert that to a unicode string:
+        self.qd_error_message.errcheck = lambda x,y,z : UNICODE(x)
         self._prototype(self.qd_log_entity, c_long, [py_object])
         self._prototype(self.qd_dispatch_configure_router, None, [self.qd_dispatch_p, py_object])
         self._prototype(self.qd_dispatch_prepare, None, [self.qd_dispatch_p])
@@ -129,6 +132,10 @@ def import_check(name, *args, **kw):
     return builtin_import(name, *args, **kw)
 
 check_forbidden()
-import __builtin__
-builtin_import = __builtin__.__import__
-__builtin__.__import__ = import_check
+try:
+    import builtins
+except:  # py2
+    import __builtin__ as builtins
+
+builtin_import = builtins.__import__
+builtins.__import__ = import_check

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/management/agent.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/management/agent.py b/python/qpid_dispatch_internal/management/agent.py
index 88e828b..6d737bb 100644
--- a/python/qpid_dispatch_internal/management/agent.py
+++ b/python/qpid_dispatch_internal/management/agent.py
@@ -64,13 +64,24 @@ data that may be updated in other threads.
 
 import traceback, json, pstats
 import socket
-from itertools import ifilter, chain
 from traceback import format_exc
 from threading import Lock
 from cProfile import Profile
-from cStringIO import StringIO
+try:
+    # py2
+    from cStringIO import StringIO
+except ImportError:
+    from io import StringIO
+
 from ctypes import c_void_p, py_object, c_long
 from subprocess import Popen
+try:
+    # Python 2
+    from future_builtins import filter
+except ImportError:
+    # Python 3
+    pass
+
 from ..dispatch import IoAdapter, LogAdapter, LOG_INFO, LOG_WARNING, LOG_DEBUG, LOG_ERROR, TREATMENT_ANYCAST_CLOSEST
 from qpid_dispatch.management.error import ManagementError, OK, CREATED, NO_CONTENT, STATUS_TEXT, \
     BadRequestStatus, InternalServerErrorStatus, NotImplementedStatus, NotFoundStatus, ForbiddenStatus
@@ -80,11 +91,12 @@ from .qdrouter import QdSchema
 from ..router.message import Message
 from ..router.address import Address
 from ..policy.policy_manager import PolicyManager
+from qpid_dispatch_internal.compat import dict_iteritems
 
 
 def dictstr(d):
     """Stringify a dict in the form 'k=v, k=v ...' instead of '{k:v, ...}'"""
-    return ", ".join("%s=%r" % (k, v) for k, v in d.iteritems())
+    return ", ".join("%s=%r" % (k, v) for k, v in dict_iteritems(d))
 
 def required_property(prop, request):
     """Raise exception if required property is missing"""
@@ -436,7 +448,7 @@ class ConsoleEntity(EntityAdapter):
                                 dargs['$wsport'] = wsport
                             if home:
                                 dargs['$home'] = home
-                            for k,v in dargs.iteritems():
+                            for k,v in dict_iteritems(dargs):
                                 args = args.replace(k,str(v))
                             pargs += args.split()
 
@@ -517,15 +529,22 @@ class EntityCache(object):
 
     def map_filter(self, function, test):
         """Filter with test then apply function."""
-        return map(function, ifilter(test, self.entities))
+        if function is None:
+            function = lambda x: x  # return results of filter
+        return list(map(function, filter(test, self.entities)))
 
     def map_type(self, function, type):
-        """Apply function to all entities of type, if type is None do all entities"""
+        """Apply function to all entities of type, if type is None do all
+        entities"""
+        if function is None:
+            function = lambda x: x
         if type is None:
-            return map(function, self.entities)
+            return list(map(function, self.entities))
         else:
-            if not isinstance(type, EntityType): type = self.schema.entity_type(type)
-            return map(function, ifilter(lambda e: e.entity_type.is_a(type), self.entities))
+            if not isinstance(type, EntityType):
+                type = self.schema.entity_type(type)
+            return list(map(function, filter(lambda e: e.entity_type.is_a(type),
+                                             self.entities)))
 
     def add(self, entity):
         """Add an entity to the agent"""
@@ -575,7 +594,7 @@ class EntityCache(object):
             """Remove redundant add/remove pairs of events."""
             add = {}            # add[pointer] = index of add event.
             redundant = []      # List of redundant event indexes.
-            for i in xrange(len(events)):
+            for i in range(len(events)):
                 action, type, pointer = events[i]
                 if action == ADD:
                     add[pointer] = i
@@ -620,13 +639,13 @@ class ManagementEntity(EntityAdapter):
         """Management node query operation"""
         entity_type = self.requested_type(request)
         if entity_type:
-            all_attrs = set(entity_type.attributes.keys())
+            all_attrs = list(entity_type.attributes.keys())
         else:
-            all_attrs = self._schema.all_attributes
+            all_attrs = list(self._schema.all_attributes)
 
-        names = set(request.body.get('attributeNames'))
+        names = request.body.get('attributeNames')
         if names:
-            unknown = names - all_attrs
+            unknown = set(names) - set(all_attrs)
             if unknown:
                 if entity_type:
                     for_type = " for type %s" % entity_type.name
@@ -646,7 +665,7 @@ class ManagementEntity(EntityAdapter):
             if non_empty: results.append(result)
 
         self._agent.entities.map_type(add_result, entity_type)
-        return (OK, {'attributeNames': list(names), 'results': results})
+        return (OK, {'attributeNames': names, 'results': results})
 
     def get_types(self, request):
         type = self.requested_type(request)
@@ -662,13 +681,13 @@ class ManagementEntity(EntityAdapter):
     def get_operations(self, request):
         type = self.requested_type(request)
         return (OK, dict((t, et.operations)
-                         for t, et in self._schema.entity_types.iteritems()
+                         for t, et in dict_iteritems(self._schema.entity_types)
                          if not type or type.name == t))
 
     def get_attributes(self, request):
         type = self.requested_type(request)
         return (OK, dict((t, [a for a in et.attributes])
-                         for t, et in self._schema.entity_types.iteritems()
+                         for t, et in dict_iteritems(self._schema.entity_types)
                          if not type or type.name == t))
 
     def get_mgmt_nodes(self, request):
@@ -786,7 +805,7 @@ class Agent(object):
         """Called when a management request is received."""
         def error(e, trace):
             """Raise an error"""
-            self.log(LOG_ERROR, "Error performing %s: %s"%(request.properties.get('operation'), e.message))
+            self.log(LOG_ERROR, "Error performing %s: %s"%(request.properties.get('operation'), e.description))
             self.respond(request, e.status, e.description)
 
         # If there's no reply_to, don't bother to process the request.
@@ -800,16 +819,16 @@ class Agent(object):
                 self.log(LOG_DEBUG, "Agent request %s"% request)
                 status, body = self.handle(request)
                 self.respond(request, status=status, body=body)
-            except ManagementError, e:
+            except ManagementError as e:
                 error(e, format_exc())
-            except ValidationError, e:
+            except ValidationError as e:
                 error(BadRequestStatus(str(e)), format_exc())
-            except Exception, e:
+            except Exception as e:
                 error(InternalServerErrorStatus("%s: %s"%(type(e).__name__, e)), format_exc())
 
     def entity_type(self, type):
         try: return self.schema.entity_type(type)
-        except ValidationError, e: raise NotFoundStatus(str(e))
+        except ValidationError as e: raise NotFoundStatus(str(e))
 
     def handle(self, request):
         """
@@ -904,9 +923,9 @@ class Agent(object):
 
         def attrvals():
             """String form of the id attribute values for error messages"""
-            return " ".join(["%s=%r" % (k, v) for k, v in ids.iteritems()])
+            return " ".join(["%s=%r" % (k, v) for k, v in dict_iteritems(ids)])
 
-        k, v = ids.iteritems().next() # Get the first id attribute
+        k, v = next(dict_iteritems(ids)) # Get the first id attribute
         found = self.entities.map_filter(None, lambda e: e.attributes.get(k) == v)
         if len(found) == 1:
             entity = found[0]
@@ -916,7 +935,7 @@ class Agent(object):
         else:
             raise NotFoundStatus("No entity with %s" % attrvals())
 
-        for k, v in ids.iteritems():
+        for k, v in dict_iteritems(ids):
             if entity[k] != v: raise BadRequestStatus("Conflicting %s" % attrvals())
 
         if requested_type:

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/management/config.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/management/config.py b/python/qpid_dispatch_internal/management/config.py
index 303609e..24a6f04 100644
--- a/python/qpid_dispatch_internal/management/config.py
+++ b/python/qpid_dispatch_internal/management/config.py
@@ -28,19 +28,24 @@ from qpid_dispatch.management.entity import camelcase
 
 from ..dispatch import QdDll
 from .qdrouter import QdSchema
+from qpid_dispatch_internal.compat import dict_itervalues
+from qpid_dispatch_internal.compat import dict_iteritems
+from qpid_dispatch_internal.compat import PY_STRING_TYPE
+from qpid_dispatch_internal.compat import PY_TEXT_TYPE
 
 class Config(object):
     """Load config entities from qdrouterd.conf and validated against L{QdSchema}."""
 
     def __init__(self, filename=None, schema=QdSchema(), raw_json=False):
         self.schema = schema
-        self.config_types = [et for et in schema.entity_types.itervalues()
+        self.config_types = [et for et in dict_itervalues(schema.entity_types)
                              if schema.is_configuration(et)]
         if filename:
             try:
                 self.load(filename, raw_json)
-            except Exception, e:
-                raise Exception, "Cannot load configuration file %s: %s" % (filename, e), sys.exc_info()[2]
+            except Exception as e:
+                raise Exception("Cannot load configuration file %s: %s"
+                                % (filename, e))
         else:
             self.entities = []
 
@@ -48,7 +53,7 @@ class Config(object):
     def transform_sections(sections):
         for s in sections:
             s[0] = camelcase(s[0])
-            s[1] = dict((camelcase(k), v) for k, v in s[1].iteritems())
+            s[1] = dict((camelcase(k), v) for k, v in dict_iteritems(s[1]))
             if s[0] == "address":   s[0] = "router.config.address"
             if s[0] == "linkRoute": s[0] = "router.config.linkRoute"
             if s[0] == "autoLink":  s[0] = "router.config.autoLink"
@@ -111,7 +116,7 @@ class Config(object):
         @param source: A file name, open file object or iterable list of lines
         @param raw_json: Source is pure json not needing conf-style substitutions
         """
-        if isinstance(source, basestring):
+        if isinstance(source, (PY_STRING_TYPE, PY_TEXT_TYPE)):
             raw_json |= source.endswith(".json")
             with open(source) as f:
                 self.load(f, raw_json)

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/management/qdrouter.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/management/qdrouter.py b/python/qpid_dispatch_internal/management/qdrouter.py
index efb9965..e26b96b 100644
--- a/python/qpid_dispatch_internal/management/qdrouter.py
+++ b/python/qpid_dispatch_internal/management/qdrouter.py
@@ -24,7 +24,7 @@ Qpid Dispatch Router management schema and config file parsing.
 import json
 from pkgutil import get_data
 from . import schema
-from ..compat import JSON_LOAD_KWARGS
+from qpid_dispatch_internal.compat import JSON_LOAD_KWARGS
 
 class QdSchema(schema.Schema):
     """
@@ -39,7 +39,7 @@ class QdSchema(schema.Schema):
         qd_schema = get_data('qpid_dispatch.management', 'qdrouter.json')
         try:
             super(QdSchema, self).__init__(**json.loads(qd_schema, **JSON_LOAD_KWARGS))
-        except Exception,e:
+        except Exception as e:
             raise ValueError("Invalid schema qdrouter.json: %s" % e)
         self.configuration_entity = self.entity_type(self.CONFIGURATION_ENTITY)
         self.operational_entity = self.entity_type(self.OPERATIONAL_ENTITY)

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/management/schema.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/management/schema.py b/python/qpid_dispatch_internal/management/schema.py
index 7427851..6e619e7 100644
--- a/python/qpid_dispatch_internal/management/schema.py
+++ b/python/qpid_dispatch_internal/management/schema.py
@@ -31,6 +31,10 @@ import traceback
 from qpid_dispatch.management.entity import EntityBase
 from qpid_dispatch.management.error import NotImplementedStatus
 from ..compat import OrderedDict
+from ..compat import PY_STRING_TYPE
+from ..compat import PY_TEXT_TYPE
+from ..compat import dict_keys
+from ..compat import dict_items
 try:
     from ..dispatch import LogAdapter, LOG_WARNING
     logger_available = True
@@ -89,7 +93,7 @@ class BooleanType(Type):
         @return A python bool.
         """
         try:
-            if isinstance(value, basestring):
+            if isinstance(value, (PY_STRING_TYPE, PY_TEXT_TYPE)):
                 return self.VALUES[value.lower()]
             return bool(value)
         except:
@@ -104,6 +108,7 @@ class EnumValue(str):
         setattr(s, 'value', value)
         return s
 
+    def __hash__(self): return super(EnumValue, self).__hash__()
     def __int__(self): return self.value
     def __eq__(self, x): return str(self) == x or int(self) == x
     def __ne__(self, x): return not self == x
@@ -217,9 +222,11 @@ class AttributeType(object):
             self.create=create
             self.update=update
             self.graph=graph
-        except:
-            ex, msg, trace = sys.exc_info()
-            raise ValidationError, "Attribute '%s': %s" % (name, msg), trace
+        except Exception:
+            raise ValidationError("Attribute '%s': %s\n%s"
+                                  % (name,
+                                     sys.exc_info()[1],
+                                     sys.exc_info()[2]))
 
     def missing_value(self):
         """
@@ -243,8 +250,8 @@ class AttributeType(object):
                 self.name, self.value, value))
         try:
             return self.atype.validate(value)
-        except (TypeError, ValueError), e:
-            raise ValidationError, str(e), sys.exc_info()[2]
+        except (TypeError, ValueError) as e:
+            raise ValidationError("%s:%s" % (str(e), sys.exc_info()[2]))
 
     def dump(self):
         """
@@ -270,7 +277,7 @@ class MessageDef(object):
         self.body = None
         if body: self.body = AttributeType("body", **body)
         self.properties = dict((name, AttributeType(name, **value))
-                               for name, value in (properties or {}).iteritems())
+                               for name, value in (properties or {}).items())
 
 
 class OperationDef(object):
@@ -282,9 +289,9 @@ class OperationDef(object):
             self.request = self.response = None
             if request: self.request = MessageDef(**request)
             if response: self.response = MessageDef(**response)
-        except:
-            ex, msg, trace = sys.exc_info()
-            raise ValidationError, "Operation '%s': %s" % (name, msg), trace
+        except Exception as exc:
+            raise ValidationError("Operation '%s': %s\n%s"
+                                  % (name, str(exc), sys.exc_info()[2]))
 
 
 class EntityType(object):
@@ -320,7 +327,7 @@ class EntityType(object):
             else:
                 self.name = self.short_name = name
             self.attributes = OrderedDict((k, AttributeType(k, defined_in=self, **v))
-                                              for k, v in (attributes or {}).iteritems())
+                                              for k, v in (attributes or {}).items())
 
             self.deprecated_attributes = OrderedDict()
             for key, value in self.attributes.items():
@@ -357,10 +364,12 @@ class EntityType(object):
             self._init = False      # Have not yet initialized from base and attributes.
             # Operation definitions
             self.operation_defs = dict((name, OperationDef(name, **op))
-                                  for name, op in (operationDefs or {}).iteritems())
-        except:
-            ex, msg, trace = sys.exc_info()
-            raise ValidationError, "%s '%s': %s" % (type(self).__name__, name, msg), trace
+                                  for name, op in (operationDefs or {}).items())
+        except Exception as exc:
+            raise ValidationError("%s '%s': %s\n%s" % (type(self).__name__,
+                                                       name,
+                                                       exc,
+                                                       sys.exc_info()[2]))
 
     def init(self):
         """Find bases after all types are loaded."""
@@ -381,7 +390,7 @@ class EntityType(object):
                                       % (self.name, how, other.short_name, what, ",".join(overlap)))
         check(self.operations, other.operations, "operations")
         self.operations += other.operations
-        check(self.attributes.iterkeys(), other.attributes.itervalues(), "attributes")
+        check(dict_keys(self.attributes), other.attributes.values(), "attributes")
         self.attributes.update(other.attributes)
         if other.name == 'entity':
             # Fill in entity "type" attribute automatically.
@@ -393,7 +402,7 @@ class EntityType(object):
 
     def attribute(self, name):
         """Get the AttributeType for name"""
-        if not name in self.attributes and not name in self.deprecated_attributes.keys():
+        if not name in self.attributes and not name in dict_keys(self.deprecated_attributes):
             raise ValidationError("Unknown attribute '%s' for '%s'" % (name, self))
         if self.attributes.get(name):
             return self.attributes[name]
@@ -407,7 +416,7 @@ class EntityType(object):
     @property
     def my_attributes(self):
         """Return only attribute types defined in this entity type"""
-        return [a for a in self.attributes.itervalues() if a.defined_in == self]
+        return [a for a in self.attributes.values() if a.defined_in == self]
 
     def validate(self, attributes):
         """
@@ -419,7 +428,7 @@ class EntityType(object):
 
         try:
             # Add missing values
-            for attr in self.attributes.itervalues():
+            for attr in self.attributes.values():
                 if attributes.get(attr.name) is None:
                     value = None
                     deprecation_name = attr.deprecation_name
@@ -449,12 +458,12 @@ class EntityType(object):
                                                   (deprecation_name, attr.name, self.short_name))
 
             # Validate attributes.
-            for name, value in attributes.iteritems():
+            for name, value in dict_items(attributes):
                 if name == 'type':
                     value = self.schema.long_name(value)
                 attributes[name] = self.attribute(name).validate(value)
-        except ValidationError, e:
-            raise ValidationError, "%s: %s"%(self, e), sys.exc_info()[2]
+        except ValidationError as e:
+            raise ValidationError("%s: %s" % (self, e))
 
         return attributes
 
@@ -471,7 +480,7 @@ class EntityType(object):
                 raise ValidationError("Cannot set attribute '%s' in CREATE" % a)
 
     def update_check(self, new_attributes, old_attributes):
-        for a, v in new_attributes.iteritems():
+        for a, v in new_attributes.items():
             # Its not an error to include an attribute in UPDATE if the value is not changed.
             if not self.attribute(a).update and \
                not (a in old_attributes and old_attributes[a] == v):
@@ -481,7 +490,7 @@ class EntityType(object):
         """Json friendly representation"""
         return _dump_dict([
             ('attributes', OrderedDict(
-                (k, v.dump()) for k, v in self.attributes.iteritems()
+                (k, v.dump()) for k, v in self.attributes.items()
                 if k != 'type')), # Don't dump 'type' attribute, dumped separately.
             ('operations', self.operations),
             ('description', self.description or None),
@@ -529,15 +538,15 @@ class Schema(object):
 
         def parsedefs(cls, defs):
             return OrderedDict((self.long_name(k), cls(k, self, **v))
-                               for k, v in (defs or {}).iteritems())
+                               for k, v in (defs or {}).items())
 
         self.entity_types = parsedefs(EntityType, entityTypes)
 
         self.all_attributes = set()
 
-        for e in self.entity_types.itervalues():
+        for e in self.entity_types.values():
             e.init()
-            self.all_attributes.update(e.attributes.keys())
+            self.all_attributes.update(dict_keys(e.attributes))
 
     def log(self, level, text):
         if not self.log_adapter:
@@ -564,7 +573,7 @@ class Schema(object):
         return OrderedDict([
             ('prefix', self.prefix),
             ('entityTypes',
-             OrderedDict((e.short_name, e.dump()) for e in self.entity_types.itervalues()))
+             OrderedDict((e.short_name, e.dump()) for e in self.entity_types.values()))
         ])
 
     def _lookup(self, map, name, message, error):
@@ -622,7 +631,7 @@ class Schema(object):
 
     def entity(self, attributes):
         """Convert an attribute map into an L{SchemaEntity}"""
-        attributes = dict((k, v) for k, v in attributes.iteritems() if v is not None)
+        attributes = dict((k, v) for k, v in attributes.items() if v is not None)
         return SchemaEntity(self.entity_type(attributes['type']), attributes)
 
     def entities(self, attribute_maps):
@@ -631,14 +640,14 @@ class Schema(object):
 
     def filter(self, predicate):
         """Return an iterator over entity types that satisfy predicate."""
-        if predicate is None: return self.entity_types.itervalues()
-        return (t for t in self.entity_types.itervalues() if predicate(t))
+        if predicate is None: return self.entity_types.values()
+        return (t for t in self.entity_types.values() if predicate(t))
 
     def by_type(self, type):
         """Return an iterator over entity types that extend or are type.
         If type is None return all entities."""
         if not type:
-            return self.entity_types.itervalues()
+            return self.entity_types.values()
         else:
             return self.filter(lambda t: t.is_a(type))
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/management/schema_doc.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/management/schema_doc.py b/python/qpid_dispatch_internal/management/schema_doc.py
index 676fe50..d5bbf50 100644
--- a/python/qpid_dispatch_internal/management/schema_doc.py
+++ b/python/qpid_dispatch_internal/management/schema_doc.py
@@ -19,9 +19,12 @@
 
 """Library for generating asciidoc documentation from a L{schema.Schema}"""
 
+from __future__ import print_function
+
 from collections import namedtuple
 import sys
 from .schema import AttributeType
+from qpid_dispatch_internal.compat import PY_STRING_TYPE, dict_itervalues
 
 class SchemaWriter(object):
     """Write the schema as an asciidoc document"""
@@ -32,7 +35,7 @@ class SchemaWriter(object):
         # Options affecting how output is written
 
     def warn(self, message):
-        if not self.quiet: print >>sys.stderr, message
+        if not self.quiet: print(message, file=sys.stderr)
 
     def write(self, text): self.output.write(text)
 
@@ -52,7 +55,7 @@ class SchemaWriter(object):
 
     def attribute_qualifiers(self, attr, show_create=True, show_update=True):
         default = attr.default
-        if isinstance(default, basestring) and default.startswith('$'):
+        if isinstance(default, PY_STRING_TYPE) and default.startswith('$'):
             default = None  # Don't show defaults that are references, confusing.
         return ' (%s)' % (', '.join(
             filter(None, [str(attr.atype),
@@ -100,7 +103,7 @@ class SchemaWriter(object):
                         message.body.description))
                 if message.properties:
                     self.para(".%s properties" % (what.capitalize()))
-                    for prop in message.properties.itervalues():
+                    for prop in dict_itervalues(message.properties):
                         self.attribute_type(prop)
 
         with self.section("Operation %s" % op.name):
@@ -109,7 +112,7 @@ class SchemaWriter(object):
             request_response("response")
 
     def operation_defs(self, entity_type):
-        for op in entity_type.operation_defs.itervalues():
+        for op in dict_itervalues(entity_type.operation_defs):
             self.operation_def(op, entity_type)
 
     def entity_type(self, entity_type, operation_defs=True):

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/policy/policy_local.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/policy/policy_local.py b/python/qpid_dispatch_internal/policy/policy_local.py
index b482b7f..9218a56 100644
--- a/python/qpid_dispatch_internal/policy/policy_local.py
+++ b/python/qpid_dispatch_internal/policy/policy_local.py
@@ -23,7 +23,12 @@
 
 import json
 import pdb
-from policy_util import PolicyError, HostStruct, HostAddr, PolicyAppConnectionMgr, is_ipv6_enabled
+from .policy_util import PolicyError, HostStruct, HostAddr, PolicyAppConnectionMgr, is_ipv6_enabled
+from ..compat import PY_STRING_TYPE
+from ..compat import PY_TEXT_TYPE
+from ..compat import dict_iteritems
+from ..compat import dict_keys
+
 
 """
 Entity implementing the business logic of user connection/access policy.
@@ -148,7 +153,7 @@ class PolicyCompiler(object):
         """
         try:
             v_int = int(val)
-        except Exception, e:
+        except Exception as e:
             errors.append("Value '%s' does not resolve to an integer." % val)
             return False
         if v_int < v_min:
@@ -178,15 +183,11 @@ class PolicyCompiler(object):
         """
         key = PolicyKeys.KW_REMOTE_HOSTS
         # convert val string to list of host specs
-        if type(val) is str:
-            # 'abc, def, mytarget'
-            val = [x.strip(' ') for x in val.split(PolicyKeys.KC_CONFIG_LIST_SEP)]
-        elif type(val) is list:
+        if isinstance(val, list):
             # ['abc', 'def', 'mytarget']
             pass
-        elif type(val) is unicode:
-            # u'abc, def, mytarget'
-            val = [x.strip(' ') for x in str(val).split(PolicyKeys.KC_CONFIG_LIST_SEP)]
+        elif isinstance(val, (PY_STRING_TYPE, PY_TEXT_TYPE)):
+            val = [x.strip(' ') for x in val.split(PolicyKeys.KC_CONFIG_LIST_SEP)]
         else:
             errors.append(
                 "Policy vhost '%s' user group '%s' option '%s' has illegal value '%s'. Type must be 'str' or 'list' but is '%s;" %
@@ -196,7 +197,7 @@ class PolicyCompiler(object):
             try:
                 coha = HostAddr(coname, PolicyKeys.KC_CONFIG_IP_SEP)
                 list_out.append(coha)
-            except Exception, e:
+            except Exception as e:
                 errors.append("Policy vhost '%s' user group '%s' option '%s' connectionOption '%s' failed to translate: '%s'." %
                                 (vhostname, groupname, key, coname, e))
                 return False
@@ -238,7 +239,7 @@ class PolicyCompiler(object):
         user_targets = False
         user_src_pattern = False
         user_tgt_pattern = False
-        for key, val in policy_in.iteritems():
+        for key, val in dict_iteritems(policy_in):
             if key not in self.allowed_settings_options:
                 warnings.append("Policy vhost '%s' user group '%s' option '%s' is ignored." %
                                 (vhostname, usergroup, key))
@@ -277,15 +278,12 @@ class PolicyCompiler(object):
                          PolicyKeys.KW_TARGET_PATTERN
                          ]:
                 # accept a string or list
-                if type(val) is str:
-                    # 'abc, def, mytarget'
-                    val = [x.strip(' ') for x in val.split(PolicyKeys.KC_CONFIG_LIST_SEP)]
-                elif type(val) is list:
+                if isinstance(val, list):
                     # ['abc', 'def', 'mytarget']
                     pass
-                elif type(val) is unicode:
-                    # u'abc, def, mytarget'
-                    val = [x.strip(' ') for x in str(val).split(PolicyKeys.KC_CONFIG_LIST_SEP)]
+                elif isinstance(val, (PY_STRING_TYPE, PY_TEXT_TYPE)):
+                    # 'abc, def, mytarget'
+                    val = [x.strip(' ') for x in val.split(PolicyKeys.KC_CONFIG_LIST_SEP)]
                 else:
                     errors.append("Policy vhost '%s' user group '%s' option '%s' has illegal value '%s'. Type must be 'str' or 'list' but is '%s;" %
                                   (vhostname, usergroup, key, val, type(val)))
@@ -335,7 +333,7 @@ class PolicyCompiler(object):
         policy_out[PolicyKeys.KW_GROUPS] = {}
 
         # validate the options
-        for key, val in policy_in.iteritems():
+        for key, val in dict_iteritems(policy_in):
             if key not in self.allowed_ruleset_options:
                 warnings.append("Policy vhost '%s' option '%s' is ignored." %
                                 (name, key))
@@ -360,7 +358,7 @@ class PolicyCompiler(object):
                     errors.append("Policy vhost '%s' option '%s' must be of type 'dict' but is '%s'" %
                                   (name, key, type(val)))
                     return False
-                for skey, sval in val.iteritems():
+                for skey, sval in dict_iteritems(val):
                     newsettings = {}
                     if not self.compile_app_settings(name, skey, sval, newsettings, warnings, errors):
                         return False
@@ -371,7 +369,7 @@ class PolicyCompiler(object):
         # Create user-to-group map for looking up user's group
         policy_out[PolicyKeys.RULESET_U2G_MAP] = {}
         if PolicyKeys.KW_GROUPS in policy_out:
-            for group, groupsettings in policy_out[PolicyKeys.KW_GROUPS].iteritems():
+            for group, groupsettings in dict_iteritems(policy_out[PolicyKeys.KW_GROUPS]):
                 if PolicyKeys.KW_USERS in groupsettings:
                     users = [x.strip(' ') for x in groupsettings[PolicyKeys.KW_USERS].split(PolicyKeys.KC_CONFIG_LIST_SEP)]
                     for user in users:
@@ -449,7 +447,7 @@ class AppStats(object):
 
 #
 #
-class ConnectionFacts:
+class ConnectionFacts(object):
     def __init__(self, user, host, app, conn_name):
         self.user = user
         self.host = host
@@ -554,7 +552,7 @@ class PolicyLocal(object):
         """
         Return a list of vhost names in this policy
         """
-        return self.rulesetdb.keys()
+        return dict_keys(self.rulesetdb)
 
     def set_default_vhost(self, name):
         """
@@ -662,7 +660,7 @@ class PolicyLocal(object):
             # Return success
             return usergroup
 
-        except Exception, e:
+        except Exception as e:
             self._manager.log_info(
                 "DENY AMQP Open lookup_user failed for user '%s', rhost '%s', vhost '%s': "
                 "Internal error: %s" % (user, rhost, vhost, e))
@@ -702,7 +700,7 @@ class PolicyLocal(object):
             upolicy.update(ruleset[PolicyKeys.KW_GROUPS][groupname])
             upolicy[PolicyKeys.KW_CSTATS] = self.statsdb[vhost].get_cstats()
             return True
-        except Exception, e:
+        except Exception as e:
             return False
 
     def close_connection(self, conn_id):
@@ -717,7 +715,7 @@ class PolicyLocal(object):
                 stats = self.statsdb[facts.app]
                 stats.disconnect(facts.conn_name, facts.user, facts.host)
                 del self._connections[conn_id]
-        except Exception, e:
+        except Exception as e:
             self._manager.log_trace(
                 "Policy internal error closing connection id %s. %s" % (conn_id, str(e)))
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/policy/policy_manager.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/policy/policy_manager.py b/python/qpid_dispatch_internal/policy/policy_manager.py
index 34deabb..0445386 100644
--- a/python/qpid_dispatch_internal/policy/policy_manager.py
+++ b/python/qpid_dispatch_internal/policy/policy_manager.py
@@ -23,7 +23,8 @@
 
 import json
 import traceback
-from policy_local import PolicyLocal
+
+from .policy_local import PolicyLocal
 from ..dispatch import LogAdapter, LOG_INFO, LOG_TRACE, LOG_DEBUG, LOG_ERROR, LOG_WARNING
 
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/policy/policy_util.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/policy/policy_util.py b/python/qpid_dispatch_internal/policy/policy_util.py
index eaf8993..b74f7b5 100644
--- a/python/qpid_dispatch_internal/policy/policy_util.py
+++ b/python/qpid_dispatch_internal/policy/policy_util.py
@@ -88,7 +88,7 @@ class HostStruct(object):
             self.family = sfamily
             self.binary = socket.inet_pton(family, saddr)
             return
-        except Exception, e:
+        except Exception as e:
             raise PolicyError("HostStruct: '%s' failed to resolve: '%s'" %
                               (hostname, e))
 
@@ -201,7 +201,7 @@ class HostAddr(object):
             return c0 >= 0 and c1 <= 0
         except PolicyError:
             return False
-        except Exception, e:
+        except Exception as e:
             assert isinstance(candidate, HostStruct), \
                 ("Wrong type. Expected HostStruct but received %s" % candidate.__class__.__name__)
             return False
@@ -341,4 +341,4 @@ class PolicyAppConnectionMgr(object):
         Record the statistic for a connection denied by some other process
         @return:
         """
-        self.connections_denied += 1
\ No newline at end of file
+        self.connections_denied += 1

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/router/__init__.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/router/__init__.py b/python/qpid_dispatch_internal/router/__init__.py
index 27bcf09..0c1682d 100644
--- a/python/qpid_dispatch_internal/router/__init__.py
+++ b/python/qpid_dispatch_internal/router/__init__.py
@@ -18,6 +18,6 @@
 #
 
 from .engine import RouterEngine
-from address import Address
+from .address import Address
 
 __all__ = ["RouterEngine", "Address"]

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/router/data.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/router/data.py b/python/qpid_dispatch_internal/router/data.py
index a2b669b..827f621 100644
--- a/python/qpid_dispatch_internal/router/data.py
+++ b/python/qpid_dispatch_internal/router/data.py
@@ -21,7 +21,10 @@
 ## Define the current protocol version.  Any messages that do not contain version
 ## information shall be considered to be coming from routers using version 0.
 ##
-ProtocolVersion = 1L
+from ..compat import PY_LONG_TYPE
+from ..compat import LONG
+
+ProtocolVersion = LONG(1)
 
 def getMandatory(data, key, cls=None):
     """
@@ -57,12 +60,12 @@ class LinkState(object):
         if body:
             self.id = getMandatory(body, 'id', str)
             self.area = '0'
-            self.ls_seq = getMandatory(body, 'ls_seq', long)
+            self.ls_seq = getMandatory(body, 'ls_seq', PY_LONG_TYPE)
             self.peers = getMandatory(body, 'peers', dict)
         else:
             self.id = _id
             self.area = '0'
-            self.ls_seq = long(_ls_seq)
+            self.ls_seq = LONG(_ls_seq)
             self.peers = _peers
 
     def __repr__(self):
@@ -107,13 +110,13 @@ class MessageHELLO(object):
     This message is used by directly connected routers to determine with whom they have
     bidirectional connectivity.
     """
-    def __init__(self, body, _id=None, _seen_peers=None, _instance=long(0)):
+    def __init__(self, body, _id=None, _seen_peers=None, _instance=LONG(0)):
         if body:
             self.id = getMandatory(body, 'id', str)
             self.area = '0'
             self.seen_peers = getMandatory(body, 'seen', list)
-            self.instance = getOptional(body, 'instance', 0, long)
-            self.version  = getOptional(body, 'pv', 0, long)
+            self.instance = getOptional(body, 'instance', 0, PY_LONG_TYPE)
+            self.version  = getOptional(body, 'pv', 0, PY_LONG_TYPE)
         else:
             self.id   = _id
             self.area = '0'
@@ -145,19 +148,19 @@ class MessageRA(object):
     This message is sent periodically to indicate the originating router's sequence numbers
     for link-state and mobile-address-state.
     """
-    def __init__(self, body, _id=None, _ls_seq=None, _mobile_seq=None, _instance=long(0)):
+    def __init__(self, body, _id=None, _ls_seq=None, _mobile_seq=None, _instance=LONG(0)):
         if body:
             self.id = getMandatory(body, 'id', str)
             self.area = '0'
-            self.ls_seq = getMandatory(body, 'ls_seq', long)
-            self.mobile_seq = getMandatory(body, 'mobile_seq', long)
-            self.instance = getOptional(body, 'instance', 0, long)
-            self.version  = getOptional(body, 'pv', 0, long)
+            self.ls_seq = getMandatory(body, 'ls_seq', PY_LONG_TYPE)
+            self.mobile_seq = getMandatory(body, 'mobile_seq', PY_LONG_TYPE)
+            self.instance = getOptional(body, 'instance', 0, PY_LONG_TYPE)
+            self.version  = getOptional(body, 'pv', 0, PY_LONG_TYPE)
         else:
             self.id = _id
             self.area = '0'
-            self.ls_seq = long(_ls_seq)
-            self.mobile_seq = long(_mobile_seq)
+            self.ls_seq = LONG(_ls_seq)
+            self.mobile_seq = LONG(_mobile_seq)
             self.instance = _instance
             self.version  = ProtocolVersion
 
@@ -180,18 +183,18 @@ class MessageRA(object):
 class MessageLSU(object):
     """
     """
-    def __init__(self, body, _id=None, _ls_seq=None, _ls=None, _instance=long(0)):
+    def __init__(self, body, _id=None, _ls_seq=None, _ls=None, _instance=LONG(0)):
         if body:
             self.id = getMandatory(body, 'id', str)
             self.area = '0'
-            self.ls_seq = getMandatory(body, 'ls_seq', long)
+            self.ls_seq = getMandatory(body, 'ls_seq', PY_LONG_TYPE)
             self.ls = LinkState(getMandatory(body, 'ls', dict))
-            self.instance = getOptional(body, 'instance', 0, long)
-            self.version  = getOptional(body, 'pv', 0, long)
+            self.instance = getOptional(body, 'instance', 0, PY_LONG_TYPE)
+            self.version  = getOptional(body, 'pv', 0, PY_LONG_TYPE)
         else:
             self.id = _id
             self.area = '0'
-            self.ls_seq = long(_ls_seq)
+            self.ls_seq = LONG(_ls_seq)
             self.ls = _ls
             self.instance = _instance
             self.version  = ProtocolVersion
@@ -218,7 +221,7 @@ class MessageLSR(object):
     def __init__(self, body, _id=None):
         if body:
             self.id = getMandatory(body, 'id', str)
-            self.version = getOptional(body, 'pv', 0, long)
+            self.version = getOptional(body, 'pv', 0, PY_LONG_TYPE)
             self.area = '0'
         else:
             self.id = _id
@@ -243,9 +246,9 @@ class MessageMAU(object):
     def __init__(self, body, _id=None, _seq=None, _add_list=None, _del_list=None, _exist_list=None):
         if body:
             self.id = getMandatory(body, 'id', str)
-            self.version = getOptional(body, 'pv', 0, long)
+            self.version = getOptional(body, 'pv', 0, PY_LONG_TYPE)
             self.area = '0'
-            self.mobile_seq = getMandatory(body, 'mobile_seq', long)
+            self.mobile_seq = getMandatory(body, 'mobile_seq', PY_LONG_TYPE)
             self.add_list = getOptional(body, 'add', None, list)
             self.del_list = getOptional(body, 'del', None, list)
             self.exist_list = getOptional(body, 'exist', None, list)
@@ -253,7 +256,7 @@ class MessageMAU(object):
             self.id = _id
             self.version = ProtocolVersion
             self.area = '0'
-            self.mobile_seq = long(_seq)
+            self.mobile_seq = LONG(_seq)
             self.add_list = _add_list
             self.del_list = _del_list
             self.exist_list = _exist_list
@@ -288,14 +291,14 @@ class MessageMAR(object):
     def __init__(self, body, _id=None, _have_seq=None):
         if body:
             self.id = getMandatory(body, 'id', str)
-            self.version = getOptional(body, 'pv', 0, long)
+            self.version = getOptional(body, 'pv', 0, PY_LONG_TYPE)
             self.area = '0'
-            self.have_seq = getMandatory(body, 'have_seq', long)
+            self.have_seq = getMandatory(body, 'have_seq', PY_LONG_TYPE)
         else:
             self.id = _id
             self.version = ProtocolVersion
             self.area = '0'
-            self.have_seq = long(_have_seq)
+            self.have_seq = LONG(_have_seq)
 
     def get_opcode(self):
         return 'MAR'

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/router/engine.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/router/engine.py b/python/qpid_dispatch_internal/router/engine.py
index aefaa5c..ef099be 100644
--- a/python/qpid_dispatch_internal/router/engine.py
+++ b/python/qpid_dispatch_internal/router/engine.py
@@ -17,13 +17,13 @@
 # under the License.
 #
 
-from data import MessageHELLO, MessageRA, MessageLSU, MessageMAU, MessageMAR, MessageLSR
-from hello import HelloProtocol
-from link import LinkStateEngine
-from path import PathEngine
-from mobile import MobileAddressEngine
-from node import NodeTracker
-from message import Message
+from .data import MessageHELLO, MessageRA, MessageLSU, MessageMAU, MessageMAR, MessageLSR
+from .hello import HelloProtocol
+from .link import LinkStateEngine
+from .path import PathEngine
+from .mobile import MobileAddressEngine
+from .node import NodeTracker
+from .message import Message
 
 from traceback import format_exc, extract_stack
 import time
@@ -35,7 +35,7 @@ import time
 from ..dispatch import IoAdapter, LogAdapter, LOG_TRACE, LOG_INFO, LOG_ERROR, LOG_STACK_LIMIT
 from ..dispatch import TREATMENT_MULTICAST_FLOOD, TREATMENT_MULTICAST_ONCE
 
-class RouterEngine:
+class RouterEngine(object):
     """
     """
 
@@ -60,7 +60,7 @@ class RouterEngine:
                                IoAdapter(self.receive, "qdhello",     'L', '0', TREATMENT_MULTICAST_FLOOD)]
         self.max_routers    = max_routers
         self.id             = router_id
-        self.instance       = long(time.time())
+        self.instance       = int(time.time())
         self.area           = area
         self.log(LOG_INFO, "Router Engine Instantiated: id=%s instance=%d max_routers=%d" %
                  (self.id, self.instance, self.max_routers))
@@ -87,8 +87,10 @@ class RouterEngine:
     @property
     def config(self):
         if not self._config:
-            try: self._config = self.router_adapter.get_agent().find_entity_by_type('router')[0]
-            except IndexError: raise ValueError("No router configuration found")
+            try:
+                self._config = self.router_adapter.get_agent().find_entity_by_type('router')[0]
+            except IndexError:
+                raise ValueError("No router configuration found")
         return self._config
 
     def addressAdded(self, addr):

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/router/hello.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/router/hello.py b/python/qpid_dispatch_internal/router/hello.py
index 177e578..6b21bc8 100644
--- a/python/qpid_dispatch_internal/router/hello.py
+++ b/python/qpid_dispatch_internal/router/hello.py
@@ -17,8 +17,11 @@
 # under the License.
 #
 
-from data import MessageHELLO
-from qpid_dispatch_internal.dispatch import LOG_INFO, LOG_TRACE, LOG_CRITICAL
+from .data import MessageHELLO
+from ..dispatch import LOG_INFO, LOG_TRACE, LOG_CRITICAL
+from ..compat import dict_keys
+from ..compat import dict_items
+
 
 class HelloProtocol(object):
     """
@@ -41,7 +44,7 @@ class HelloProtocol(object):
         self.ticks += 1.0
         if self.ticks - self.last_hello_ticks >= self.hello_interval:
             self.last_hello_ticks = self.ticks
-            msg = MessageHELLO(None, self.id, self.hellos.keys(), self.container.instance)
+            msg = MessageHELLO(None, self.id, dict_keys(self.hellos), self.container.instance)
             self.container.send('amqp:/_local/qdhello', msg)
             self.container.log_hello(LOG_TRACE, "SENT: %r" % msg)
 
@@ -62,7 +65,7 @@ class HelloProtocol(object):
         Expire local records of received hellos.  This is not involved in the
         expiration of neighbor status for routers.
         """
-        for key, last_seen in self.hellos.items():
+        for key, last_seen in dict_items(self.hellos):
             if now - last_seen > self.hello_max_age:
                 self.hellos.pop(key)
                 self.container.log_hello(LOG_TRACE, "HELLO peer expired: %s" % key)

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/router/link.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/router/link.py b/python/qpid_dispatch_internal/router/link.py
index ee051a0..09c4dfd 100644
--- a/python/qpid_dispatch_internal/router/link.py
+++ b/python/qpid_dispatch_internal/router/link.py
@@ -17,7 +17,7 @@
 # under the License.
 #
 
-from data import MessageRA, MessageLSU, MessageLSR
+from .data import MessageRA, MessageLSU, MessageLSR
 from ..dispatch import LOG_TRACE
 
 class LinkStateEngine(object):

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/router/mobile.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/router/mobile.py b/python/qpid_dispatch_internal/router/mobile.py
index 2592fe2..c29d038 100644
--- a/python/qpid_dispatch_internal/router/mobile.py
+++ b/python/qpid_dispatch_internal/router/mobile.py
@@ -17,7 +17,7 @@
 # under the License.
 #
 
-from data import MessageMAR, MessageMAU
+from .data import MessageMAR, MessageMAU
 from ..dispatch import LOG_TRACE
 
 MAX_KEPT_DELTAS = 10

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/router/node.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/router/node.py b/python/qpid_dispatch_internal/router/node.py
index 619d88a..68d40ef 100644
--- a/python/qpid_dispatch_internal/router/node.py
+++ b/python/qpid_dispatch_internal/router/node.py
@@ -18,8 +18,10 @@
 #
 
 from ..dispatch import LOG_INFO, LOG_TRACE, LOG_DEBUG
-from data import LinkState, ProtocolVersion
+from .data import LinkState, ProtocolVersion
 from .address import Address
+from ..compat import dict_items
+
 
 class NodeTracker(object):
     """
@@ -70,7 +72,7 @@ class NodeTracker(object):
         """
         Run through the list of routers and check for expired conditions
         """
-        for node_id, node in self.nodes.items():
+        for node_id, node in dict_items(self.nodes):
             ##
             ## If the node is a neighbor, check the neighbor refresh time to see
             ## if we've waited too long for a refresh.  If so, disconnect the link
@@ -275,7 +277,7 @@ class NodeTracker(object):
         ##
         ## Add the version if we haven't already done so.
         ##
-        if node.version == None:
+        if node.version is None:
             node.version = version
 
         ##
@@ -328,7 +330,7 @@ class NodeTracker(object):
         ##
         ## Add the version if we haven't already done so.
         ##
-        if node.version == None:
+        if node.version is None:
             node.version = version
 
         ##
@@ -361,13 +363,13 @@ class NodeTracker(object):
 
 
     def _allocate_maskbit(self):
-        if self.next_maskbit == None:
+        if self.next_maskbit is None:
             raise Exception("Exceeded Maximum Router Count")
         result = self.next_maskbit
         self.next_maskbit = None
         self.maskbits[result] = True
         for n in range(result + 1, self.max_routers):
-            if self.maskbits[n] == None:
+            if self.maskbits[n] is None:
                 self.next_maskbit = n
                 break
         return result
@@ -375,7 +377,7 @@ class NodeTracker(object):
 
     def _free_maskbit(self, i):
         self.maskbits[i] = None
-        if self.next_maskbit == None or i < self.next_maskbit:
+        if self.next_maskbit is None or i < self.next_maskbit:
             self.next_maskbit = i
 
 
@@ -444,7 +446,7 @@ class RouterNode(object):
 
 
     def remove_link(self):
-        if self.peer_link_id != None:
+        if self.peer_link_id is not None:
             self.peer_link_id = None
             self.adapter.remove_link(self.maskbit)
             self.log(LOG_TRACE, "Node %s link removed" % self.id)
@@ -498,7 +500,7 @@ class RouterNode(object):
 
 
     def is_neighbor(self):
-        return self.peer_link_id != None
+        return self.peer_link_id is not None
 
 
     def request_link_state(self):
@@ -515,7 +517,8 @@ class RouterNode(object):
         reachable.  There's no point in sending it a request if we don't know how to
         reach it.
         """
-        if self.need_ls_request and (self.peer_link_id != None or self.next_hop_router != None):
+        if self.need_ls_request and (self.peer_link_id is not None or
+                                     self.next_hop_router is not None):
             self.need_ls_request = False
             return True
         return False
@@ -526,7 +529,8 @@ class RouterNode(object):
 
 
     def mobile_address_requested(self):
-        if self.need_mobile_request and (self.peer_link_id != None or self.next_hop_router != None):
+        if self.need_mobile_request and (self.peer_link_id is not None or
+                                         self.next_hop_router is not None):
             self.need_mobile_request = False
             return True
         return False
@@ -566,9 +570,9 @@ class RouterNode(object):
 
 
     def update_instance(self, instance, version):
-        if instance == None:
+        if instance is None:
             return False
-        if self.instance == None:
+        if self.instance is None:
             self.instance = instance
             return False
         if self.instance == instance:

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/router/path.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/router/path.py b/python/qpid_dispatch_internal/router/path.py
index 4e215e2..548f4e8 100644
--- a/python/qpid_dispatch_internal/router/path.py
+++ b/python/qpid_dispatch_internal/router/path.py
@@ -17,6 +17,8 @@
 # under the License.
 #
 
+from ..compat import dict_items
+from ..compat import dict_keys
 
 class PathEngine(object):
     """
@@ -40,7 +42,7 @@ class PathEngine(object):
             link_states[_id] = ls.peers
             for p in ls.peers:
                 if p not in link_states:
-                    link_states[p] = {_id:1L}
+                    link_states[p] = {_id:1}
 
         ##
         ## Setup Dijkstra's Algorithm
@@ -77,7 +79,7 @@ class PathEngine(object):
         ## Remove unreachable nodes from the maps.  Note that this will also remove the
         ## root node (has no previous node) from the map.
         ##
-        for u, val in prev.items():
+        for u, val in dict_items(prev):
             if not val:
                 prev.pop(u)
                 hops.pop(u)
@@ -101,9 +103,9 @@ class PathEngine(object):
             if node != self.id:
                 valid_origin[node] = []
 
-        for root in valid_origin.keys():
+        for root in dict_keys(valid_origin):
             prev, cost, hops = self._calculate_tree_from_root(root, collection)
-            nodes = prev.keys()
+            nodes = dict_keys(prev)
             while len(nodes) > 0:
                 u = nodes[0]
                 path = [u]
@@ -127,7 +129,7 @@ class PathEngine(object):
         ## Generate the shortest-path tree with the local node as root
         ##
         prev, cost, hops = self._calculate_tree_from_root(self.id, collection)
-        nodes = prev.keys()
+        nodes = dict_keys(prev)
 
         ##
         ## We will also compute the radius of the topology.  This is the number of
@@ -156,7 +158,7 @@ class PathEngine(object):
         ##
         ## Calculate the valid origins for remote routers
         ##
-        valid_origins = self._calculate_valid_origins(prev.keys(), collection)
+        valid_origins = self._calculate_valid_origins(dict_keys(prev), collection)
 
         return (next_hops, cost, valid_origins, radius)
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/tools/command.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/tools/command.py b/python/qpid_dispatch_internal/tools/command.py
index 22415ee..6153c9e 100644
--- a/python/qpid_dispatch_internal/tools/command.py
+++ b/python/qpid_dispatch_internal/tools/command.py
@@ -20,6 +20,7 @@
 """
 Utilities for command-line programs.
 """
+from __future__ import print_function
 
 import sys, json, optparse, os
 from collections import Sequence, Mapping
@@ -44,13 +45,13 @@ def main(run, argv=sys.argv, op=None):
         run(argv)
         return 0
     except KeyboardInterrupt:
-        print
-    except UsageError, e:
+        print()
+    except UsageError as e:
         op.error(e)
-    except Exception, e:
+    except Exception as e:
         if "_QPID_DISPATCH_TOOLS_DEBUG_" in os.environ:
             raise
-        print "%s: %s" % (type(e).__name__, e)
+        print("%s: %s" % (type(e).__name__, e))
     return 1
 
 def check_args(args, maxargs=0, minargs=0):
@@ -194,7 +195,7 @@ class OptionParser(optparse.OptionParser):
     def __init__(self, *args, **kwargs):
         optparse.OptionParser.__init__(self, *args, **kwargs)
         def version_cb(*args):
-            print VERSION
+            print("%s" % VERSION)
             exit(0)
 
         self.add_option("--version", help="Print version and exit.",

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/python/qpid_dispatch_internal/tools/display.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/tools/display.py b/python/qpid_dispatch_internal/tools/display.py
index b9d38bc..86d67ac 100644
--- a/python/qpid_dispatch_internal/tools/display.py
+++ b/python/qpid_dispatch_internal/tools/display.py
@@ -17,7 +17,11 @@
 # under the License.
 #
 
+from __future__ import print_function
+
 from time import strftime, gmtime
+from qpid_dispatch_internal.compat import UNICODE
+
 
 def YN(val):
   if val:
@@ -156,7 +160,7 @@ class Display:
       for idx in range(diff):
         row.append("")
 
-    print title
+    print("%s" % title)
     if len (rows) == 0:
       return
     colWidth = []
@@ -165,10 +169,8 @@ class Display:
     for head in heads:
       width = len (head)
       for row in rows:
-        text = row[col]
-        if text.__class__ == str:
-          text = text.decode('utf-8')
-        cellWidth = len(unicode(text))
+        text = UNICODE(row[col])
+        cellWidth = len(text)
         if cellWidth > width:
           width = cellWidth
       colWidth.append (width + self.tableSpacing)
@@ -177,26 +179,24 @@ class Display:
         for i in range (colWidth[col] - len (head)):
           line = line + " "
       col = col + 1
-    print line
+    print(line)
     line = self.tablePrefix
     for width in colWidth:
       for i in range (width):
         line = line + "="
-    print line
+    print(line)
 
     for row in rows:
       line = self.tablePrefix
       col  = 0
       for width in colWidth:
-        text = row[col]
-        if text.__class__ == str:
-          text = text.decode('utf-8')
-        line = line + unicode(text)
+        text = UNICODE(row[col])
+        line = line + text
         if col < len (heads) - 1:
-          for i in range (width - len(unicode(text))):
+          for i in range (width - len(text)):
             line = line + " "
         col = col + 1
-      print line
+      print(line)
 
   def do_setTimeFormat (self, fmt):
     """ Select timestamp format """
@@ -225,7 +225,7 @@ class Display:
     result += "%ds" % (sec % 60)
     return result
 
-class Sortable:
+class Sortable(object):
   """ """
   def __init__(self, row, sortIndex):
     self.row = row
@@ -233,8 +233,8 @@ class Sortable:
     if sortIndex >= len(row):
       raise Exception("sort index exceeds row boundary")
 
-  def __cmp__(self, other):
-    return cmp(self.row[self.sortIndex], other.row[self.sortIndex])
+  def __lt__(self, other):
+    return self.row[self.sortIndex] < other.row[self.sortIndex]
 
   def getRow(self):
     return self.row

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/run.py.in
----------------------------------------------------------------------
diff --git a/run.py.in b/run.py.in
index 292e57c..5f050e2 100755
--- a/run.py.in
+++ b/run.py.in
@@ -18,6 +18,7 @@
 ## under the License
 ##
 
+from __future__ import print_function
 
 """
 Run a tool or test in a build tree with the correct PATH, PYTHONPATH, etc.
@@ -108,7 +109,7 @@ if __name__ == "__main__":
     error_prefix = ""
     try:
         if len(sys.argv) == 1:
-            print usage
+            print("%s" % usage)
         elif sys.argv[1] == '-m':
             sys.argv = sys.argv[2:]
             error_prefix = "Run python module '%s': "%(sys.argv[0])
@@ -118,19 +119,19 @@ if __name__ == "__main__":
             error_prefix = "Run python script '%s':"%(sys.argv[0])
             run_path(sys.argv[0], run_name="__main__")
         elif sys.argv[1] == '--sh':
-            for name, value in env_vars.iteritems(): print '%s="%s"'%(name, value)
-            print "export %s"%' '.join(env_vars.keys())
+            for name, value in env_vars.items(): print('%s="%s"'%(name, value))
+            print("export %s"%' '.join(env_vars.keys()))
         elif sys.argv[1] == '-x':
             args = test_runner.split() + sys.argv[2:]
             error_prefix = "Running '%s': "%(args)
             os.execvp(args[0], args)
         elif sys.argv[1].startswith('-'):
-            print usage
+            print(usage)
         else:
             args = sys.argv[1:]
             error_prefix = "Running '%s': "%(args)
             os.execvp(args[0], args)
-    except Exception, e:
-        print "%s%s: %s"%(error_prefix, type(e).__name__, e)
+    except Exception as e:
+        print("%s%s: %s"%(error_prefix, type(e).__name__, e))
         raise
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/src/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ac85bca..bc132dd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -101,6 +101,7 @@ set(qpid_dispatch_SOURCES
   server.c
   timer.c
   trace_mask.c
+  python_utils.c
   )
 
 # USE_LIBWEBSOCKETS is true only if LIBWEBSOCKETS_FOUND

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/878534ec/src/entity.c
----------------------------------------------------------------------
diff --git a/src/entity.c b/src/entity.c
index d461fc5..9128752 100644
--- a/src/entity.c
+++ b/src/entity.c
@@ -18,17 +18,17 @@
  */
 
 
-#include <Python.h>
 #include <qpid/dispatch/error.h>
 #include "dispatch_private.h"
 #include "entity.h"
+#include "python_private.h"
 
 struct qd_entity_t {
     PyObject py_object;      /* Any object supporting __set/get_item__, e.g. dict. */
 };
 
 static PyObject* qd_entity_get_py(qd_entity_t* entity, const char* attribute) {
-    PyObject *py_key = PyString_FromString(attribute);
+    PyObject *py_key = PyUnicode_FromString(attribute);
     if (!py_key) return NULL;   /* Don't set qd_error, caller will set if needed. */
     PyObject *value = PyObject_GetItem((PyObject*)entity, py_key);
     Py_DECREF(py_key);
@@ -45,11 +45,8 @@ bool qd_entity_has(qd_entity_t* entity, const char *attribute) {
 char *qd_entity_get_string(qd_entity_t *entity, const char* attribute) {
     qd_error_clear();
     PyObject *py_obj = qd_entity_get_py(entity, attribute);
-    PyObject *py_str = py_obj ? PyObject_Str(py_obj) : NULL;
-    const char *cstr = py_str ? PyString_AsString(py_str) : NULL;
-    char* str = cstr ? strdup(cstr) : NULL;
+    char *str = py_string_2_c(py_obj);
     Py_XDECREF(py_obj);
-    Py_XDECREF(py_str);
     if (!str) qd_error_py();
     return str;
 }
@@ -57,7 +54,7 @@ char *qd_entity_get_string(qd_entity_t *entity, const char* attribute) {
 long qd_entity_get_long(qd_entity_t *entity, const char* attribute) {
     qd_error_clear();
     PyObject *py_obj = qd_entity_get_py(entity, attribute);
-    long result = py_obj ? PyInt_AsLong(py_obj) : -1;
+    long result = py_obj ? PyLong_AsLong(py_obj) : -1;
     Py_XDECREF(py_obj);
     qd_error_py();
     return result;
@@ -110,7 +107,7 @@ qd_error_t qd_entity_set_py(qd_entity_t* entity, const char* attribute, PyObject
     qd_error_clear();
 
     int result = 0;
-    PyObject *py_key = PyString_FromString(attribute);
+    PyObject *py_key = PyUnicode_FromString(attribute);
     if (py_key) {
         if (py_value == NULL) {     /* Delete the attribute */
             result = PyObject_DelItem((PyObject*)entity, py_key);
@@ -132,11 +129,11 @@ qd_error_t qd_entity_set_py(qd_entity_t* entity, const char* attribute, PyObject
 }
 
 qd_error_t qd_entity_set_string(qd_entity_t *entity, const char* attribute, const char *value) {
-    return qd_entity_set_py(entity, attribute, value ? PyString_FromString(value) : 0);
+    return qd_entity_set_py(entity, attribute, value ? PyUnicode_FromString(value) : 0);
 }
 
 qd_error_t qd_entity_set_longp(qd_entity_t *entity, const char* attribute, const long *value) {
-    return qd_entity_set_py(entity, attribute, value ? PyInt_FromLong(*value) : 0);
+    return qd_entity_set_py(entity, attribute, value ? PyLong_FromLong(*value) : 0);
 }
 
 qd_error_t qd_entity_set_boolp(qd_entity_t *entity, const char *attribute, const bool *value) {
@@ -173,9 +170,9 @@ qd_error_t qd_entity_set_map_key_value_int(qd_entity_t *entity, const char *attr
     if (!key)
         return  QD_ERROR_VALUE;
 
-    PyObject *py_key = PyString_FromString(key);
-    PyObject *py_value = PyInt_FromLong(value);
-    PyObject *py_attribute = PyString_FromString(attribute);
+    PyObject *py_key = PyUnicode_FromString(key);
+    PyObject *py_value = PyLong_FromLong(value);
+    PyObject *py_attribute = PyUnicode_FromString(attribute);
 
     qd_error_t ret = QD_ERROR_NONE;
 
@@ -199,9 +196,9 @@ qd_error_t qd_entity_set_map_key_value_string(qd_entity_t *entity, const char *a
     if (!key)
         return  QD_ERROR_VALUE;
 
-    PyObject *py_key = PyString_FromString(key);
-    PyObject *py_value = PyString_FromString(value);
-    PyObject *py_attribute = PyString_FromString(attribute);
+    PyObject *py_key = PyUnicode_FromString(key);
+    PyObject *py_value = PyUnicode_FromString(value);
+    PyObject *py_attribute = PyUnicode_FromString(attribute);
 
     qd_error_t ret = QD_ERROR_NONE;
 


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