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
This commit is contained in:
Harald Jensås 2022-01-07 19:21:58 +01:00 committed by Slawek Kaplonski
parent 76b9a09591
commit 88b755c0e8
3 changed files with 31 additions and 5 deletions

View File

@ -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

View File

@ -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,

View File

@ -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 <https://bugs.launchpad.net/neutron/+bug/1956785>`_.