From 88b755c0e86414ce8d6b57d6335d22bb892eaffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Jens=C3=A5s?= Date: Fri, 7 Jan 2022 19:21:58 +0100 Subject: [PATCH] Fix collect duplicates TypeError for dict values The _collect_duplicates uses a set for duplicates. This does not work when the values in the list are dictionaries. Instead of using a set, use a list and extend the condition to only add to the list if seen and not already in dups. Closes-Bug: #1956785 Change-Id: Iad627bcfb95699febd504d7dc7fc9e8a7d813a9e --- neutron_lib/api/validators/__init__.py | 10 +++++----- .../unit/api/validators/test_validators.py | 18 ++++++++++++++++++ ...on-collect-duplicates-f4d45bf5d5abbdff.yaml | 8 ++++++++ 3 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 releasenotes/notes/fix-api-list-validation-collect-duplicates-f4d45bf5d5abbdff.yaml diff --git a/neutron_lib/api/validators/__init__.py b/neutron_lib/api/validators/__init__.py index f1856af6f..83bde1e2c 100644 --- a/neutron_lib/api/validators/__init__.py +++ b/neutron_lib/api/validators/__init__.py @@ -78,14 +78,14 @@ def _collect_duplicates(data_list): :param data_list: A list of items to check for duplicates. The list may include dict items. - :returns: A set of items that are duplicates in data_list. If no - duplicates are found, the returned set is empty. + :returns: A list of items that are duplicates in data_list. If no + duplicates are found, the returned list is empty. """ seen = [] - dups = set() + dups = [] for datum in data_list: - if datum in seen: - dups.add(datum) + if datum in seen and datum not in dups: + dups.append(datum) continue seen.append(datum) return dups diff --git a/neutron_lib/tests/unit/api/validators/test_validators.py b/neutron_lib/tests/unit/api/validators/test_validators.py index 5da007edb..0a0d0aba7 100644 --- a/neutron_lib/tests/unit/api/validators/test_validators.py +++ b/neutron_lib/tests/unit/api/validators/test_validators.py @@ -971,6 +971,24 @@ class TestAttributeValidation(base.BaseTestCase): msg = validators._validate_list_of_items_non_empty(mock.Mock(), items) self.assertEqual("List should not be empty", msg) + def test__validate_list_of_items_collect_duplicates(self): + items = ['a', 'b', 'duplicate_1', 'duplicate_2', 'duplicate_1', + 'duplicate_2', 'duplicate_2', 'c'] + msg = validators._validate_list_of_items(mock.Mock(), items) + error = ("Duplicate items in the list: '%s'" + % 'duplicate_1, duplicate_2') + self.assertEqual(error, msg) + + items = [['a', 'b'], ['c', 'd'], ['a', 'b']] + msg = validators._validate_list_of_items(mock.Mock(), items) + error = "Duplicate items in the list: '%s'" % ['a', 'b'] + self.assertEqual(error, msg) + + items = [{'a': 'b'}, {'c': 'd'}, {'a': 'b'}] + msg = validators._validate_list_of_items(mock.Mock(), items) + error = "Duplicate items in the list: '%s'" % {'a': 'b'} + self.assertEqual(error, msg) + def test_validate_dict_type(self): for value in (None, True, '1', []): self.assertEqual("'%s' is not a dictionary" % value, diff --git a/releasenotes/notes/fix-api-list-validation-collect-duplicates-f4d45bf5d5abbdff.yaml b/releasenotes/notes/fix-api-list-validation-collect-duplicates-f4d45bf5d5abbdff.yaml new file mode 100644 index 000000000..b33abede4 --- /dev/null +++ b/releasenotes/notes/fix-api-list-validation-collect-duplicates-f4d45bf5d5abbdff.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Fixed an issue where API validation for duplicate entries in list values + would fail with a TypeError in case the values in the list was of type + ``dict``. + See bug: `1956785 `_. +