From: Cedric Brandily Date: Wed, 22 Jul 2015 22:35:36 +0000 (+0200) Subject: Python 3: use a hash to sort dictionaries X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=99c9af8f7ab7c38816d4873f3b10f77364f811c4;p=openstack-build%2Fneutron-build.git Python 3: use a hash to sort dictionaries Dictionaries are unorderable in py3K. This change defines the method safe_sort_key[1] which could be used a sort function for list of dictionaries and non-dictionaries. [1] neutron.common.utils Change-Id: I9c9fae53bb3ac5b8611c92164c9630c82c2d0ceb Blueprint: neutron-python3 --- diff --git a/neutron/agent/l3/router_info.py b/neutron/agent/l3/router_info.py index 1c29d793b..4c2db3655 100644 --- a/neutron/agent/l3/router_info.py +++ b/neutron/agent/l3/router_info.py @@ -344,8 +344,10 @@ class RouterInfo(object): for existing_port in existing_ports: current_port = current_ports_dict.get(existing_port['id']) if current_port: - if sorted(existing_port['fixed_ips']) != ( - sorted(current_port['fixed_ips'])): + if (sorted(existing_port['fixed_ips'], + key=common_utils.safe_sort_key) != + sorted(current_port['fixed_ips'], + key=common_utils.safe_sort_key)): updated_ports[current_port['id']] = current_port return updated_ports diff --git a/neutron/common/utils.py b/neutron/common/utils.py index 2eb31a836..a8b79e99f 100644 --- a/neutron/common/utils.py +++ b/neutron/common/utils.py @@ -18,6 +18,7 @@ """Utilities and helper functions.""" +import collections import datetime import decimal import errno @@ -250,6 +251,13 @@ def compare_elements(a, b): return set(a) == set(b) +def safe_sort_key(value): + """Return value hash or build one for dictionaries.""" + if isinstance(value, collections.Mapping): + return sorted(value.items()) + return value + + def dict2str(dic): return ','.join("%s=%s" % (key, val) for key, val in sorted(six.iteritems(dic))) diff --git a/neutron/tests/tools.py b/neutron/tests/tools.py index 1a5183489..63f730f8c 100644 --- a/neutron/tests/tools.py +++ b/neutron/tests/tools.py @@ -87,6 +87,8 @@ expected_calls_and_values is a list of (expected_call, return_value): import unittest +from neutron.common import utils + def setup_mock_calls(mocked_call, expected_calls_and_values): return_values = [call[1] for call in expected_calls_and_values] @@ -114,7 +116,8 @@ class UnorderedList(list): def __eq__(self, other): if not isinstance(other, list): return False - return sorted(self) == sorted(other) + return (sorted(self, key=utils.safe_sort_key) == + sorted(other, key=utils.safe_sort_key)) def __neq__(self, other): return not self == other diff --git a/neutron/tests/unit/db/test_db_base_plugin_v2.py b/neutron/tests/unit/db/test_db_base_plugin_v2.py index bb505acb4..bff7f7355 100644 --- a/neutron/tests/unit/db/test_db_base_plugin_v2.py +++ b/neutron/tests/unit/db/test_db_base_plugin_v2.py @@ -728,8 +728,9 @@ class NeutronDbPluginV2TestCase(testlib_api.WebTestCase): for k in keys: self.assertIn(k, resource[res_name]) if isinstance(keys[k], list): - self.assertEqual(sorted(resource[res_name][k]), - sorted(keys[k])) + self.assertEqual( + sorted(resource[res_name][k], key=utils.safe_sort_key), + sorted(keys[k], key=utils.safe_sort_key)) else: self.assertEqual(resource[res_name][k], keys[k]) @@ -3988,8 +3989,9 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase): req = self.new_update_request('subnets', data, res['subnet']['id']) res = self.deserialize(self.fmt, req.get_response(self.api)) - self.assertEqual(sorted(res['subnet']['host_routes']), - sorted(host_routes)) + self.assertEqual( + sorted(res['subnet']['host_routes'], key=utils.safe_sort_key), + sorted(host_routes, key=utils.safe_sort_key)) self.assertEqual(res['subnet']['dns_nameservers'], dns_nameservers) diff --git a/neutron/tests/unit/extensions/test_extraroute.py b/neutron/tests/unit/extensions/test_extraroute.py index aba4815db..c3c39dc19 100644 --- a/neutron/tests/unit/extensions/test_extraroute.py +++ b/neutron/tests/unit/extensions/test_extraroute.py @@ -19,6 +19,7 @@ from oslo_utils import uuidutils from webob import exc from neutron.common import constants +from neutron.common import utils from neutron.db import extraroute_db from neutron.extensions import extraroute from neutron.extensions import l3 @@ -134,8 +135,10 @@ class ExtraRouteDBTestCaseBase(object): body = self._routes_update_prepare(r['router']['id'], None, p['port']['id'], routes) - self.assertEqual(sorted(body['router']['routes']), - sorted(routes)) + self.assertEqual( + sorted(body['router']['routes'], + key=utils.safe_sort_key), + sorted(routes, key=utils.safe_sort_key)) self._routes_update_cleanup(p['port']['id'], None, r['router']['id'], []) @@ -180,14 +183,18 @@ class ExtraRouteDBTestCaseBase(object): body = self._routes_update_prepare(r['router']['id'], None, p['port']['id'], routes_orig) - self.assertEqual(sorted(body['router']['routes']), - sorted(routes_orig)) + self.assertEqual( + sorted(body['router']['routes'], + key=utils.safe_sort_key), + sorted(routes_orig, key=utils.safe_sort_key)) body = self._routes_update_prepare(r['router']['id'], None, p['port']['id'], routes_left, skip_add=True) - self.assertEqual(sorted(body['router']['routes']), - sorted(routes_left)) + self.assertEqual( + sorted(body['router']['routes'], + key=utils.safe_sort_key), + sorted(routes_left, key=utils.safe_sort_key)) self._routes_update_cleanup(p['port']['id'], None, r['router']['id'], []) diff --git a/neutron/tests/unit/plugins/cisco/n1kv/test_n1kv_plugin.py b/neutron/tests/unit/plugins/cisco/n1kv/test_n1kv_plugin.py index caeafbf83..c7f9b7616 100644 --- a/neutron/tests/unit/plugins/cisco/n1kv/test_n1kv_plugin.py +++ b/neutron/tests/unit/plugins/cisco/n1kv/test_n1kv_plugin.py @@ -17,6 +17,7 @@ import webob.exc from neutron.api import extensions as neutron_extensions from neutron.api.v2 import attributes +from neutron.common import utils from neutron import context import neutron.db.api as db from neutron.extensions import portbindings @@ -945,7 +946,7 @@ class TestN1kvPolicyProfiles(N1kvPluginTestCase): is_admin=False) res = self._list(resource, neutron_context=ctx) self.assertEqual(len(expected_profiles), len(res[resource])) - profiles = sorted(res[resource]) + profiles = sorted(res[resource], key=utils.safe_sort_key) for i in range(len(profiles)): self.assertEqual(expected_profiles[i].id, profiles[i]['id']) @@ -1179,8 +1180,10 @@ class TestN1kvSubnets(test_plugin.TestSubnetsV2, req = self.new_update_request('subnets', data, subnet['subnet']['id']) subnet = self.deserialize(self.fmt, req.get_response(self.api)) - self.assertEqual(sorted(subnet['subnet']['host_routes']), - sorted(host_routes)) + self.assertEqual( + sorted(subnet['subnet']['host_routes'], + key=utils.safe_sort_key), + sorted(host_routes, key=utils.safe_sort_key)) self.assertEqual(sorted(subnet['subnet']['dns_nameservers']), sorted(dns_nameservers)) # In N1K we need to delete the subnet before the network diff --git a/tox.ini b/tox.ini index fc5fbbf38..ede1335bc 100644 --- a/tox.ini +++ b/tox.ini @@ -118,7 +118,9 @@ commands = python setup.py test --testr-args='{posargs: \ neutron.tests.unit.plugins.brocade.test_brocade_db \ neutron.tests.unit.plugins.brocade.test_brocade_plugin \ neutron.tests.unit.plugins.brocade.test_brocade_vlan \ + neutron.tests.unit.plugins.embrane.test_embrane_neutron_plugin \ neutron.tests.unit.plugins.oneconvergence.test_nvsd_agent \ + neutron.tests.unit.plugins.oneconvergence.test_nvsd_plugin \ neutron.tests.unit.plugins.oneconvergence.test_plugin_helper \ neutron.tests.unit.plugins.oneconvergence.test_nvsdlib \ neutron.tests.unit.plugins.ibm.test_sdnve_agent \ @@ -158,6 +160,7 @@ commands = python setup.py test --testr-args='{posargs: \ neutron.tests.unit.scheduler.test_dhcp_agent_scheduler \ neutron.tests.unit.db.test_agentschedulers_db \ neutron.tests.unit.db.test_allowedaddresspairs_db \ + neutron.tests.unit.db.test_db_base_plugin_v2 \ neutron.tests.unit.db.test_ipam_backend_mixin \ neutron.tests.unit.db.test_l3_dvr_db \ neutron.tests.unit.db.test_l3_hamode_db \ @@ -230,6 +233,7 @@ commands = python setup.py test --testr-args='{posargs: \ neutron.tests.unit.extensions.test_flavors \ neutron.tests.unit.extensions.test_l3_ext_gw_mode \ neutron.tests.unit.extensions.test_extra_dhcp_opt \ + neutron.tests.unit.extensions.test_extraroute \ neutron.tests.unit.extensions.test_netmtu \ neutron.tests.unit.extensions.test_vlantransparent \ neutron.tests.unit.extensions.extendedattribute \