fixes #7 : 'items' return always the first key of a given type associated with a value

Internally changes the key-dicts by type to use OrderedDicts.
Therefore, when requesting the items(key_type=str) for a value defined as
   m["abc", "def"] = 123
The returned item will always have the key "abc" for 123, and
never "def". Previous behavior was undefined.

Also changes tests that relied on the return order of
"items": The multi_dict is not expected to work
as an OrderedDict itself, and code should not rely on this.
This commit is contained in:
Joao S. O. Bueno 2015-03-18 11:56:47 -03:00
parent 92b2935f20
commit 6f0dc223ee

View File

@ -27,9 +27,10 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
''' '''
from collections import OrderedDict
import sys import sys
_python3 = sys.version_info.major >= 3 _python3 = sys.version_info.major >= 3
del sys
class multi_key_dict(object): class multi_key_dict(object):
""" The purpose of this type is to provide a multi-key dictionary. """ The purpose of this type is to provide a multi-key dictionary.
@ -279,7 +280,7 @@ class multi_key_dict(object):
# store direct key as a value in an intermediate dictionary # store direct key as a value in an intermediate dictionary
if(not key_type in self.__dict__): if(not key_type in self.__dict__):
self.__setattr__(key_type, dict()) self.__setattr__(key_type, OrderedDict())
self.__dict__[key_type][key] = direct_key self.__dict__[key_type][key] = direct_key
# store the value in the actual dictionary # store the value in the actual dictionary
@ -439,7 +440,7 @@ def test_multi_key_dict():
assert (current_values == vals), 'itervalues(): expected {0}, but collected {1}'.format(current_values, vals) assert (current_values == vals), 'itervalues(): expected {0}, but collected {1}'.format(current_values, vals)
#test items(int) #test items(int)
items_for_int = sorted([(32, '4'), (23, 0)]) items_for_int = sorted([(12, '4'), (23, 0)])
assert (items_for_int == sorted(m.items(int))), 'items(int): expected {0}, but collected {1}'.format(items_for_int, assert (items_for_int == sorted(m.items(int))), 'items(int): expected {0}, but collected {1}'.format(items_for_int,
sorted(m.items(int))) sorted(m.items(int)))
@ -450,13 +451,13 @@ def test_multi_key_dict():
# test items() (default - all items) # test items() (default - all items)
# we tested keys(), values(), and __get_item__ above so here we'll re-create all_items using that # we tested keys(), values(), and __get_item__ above so here we'll re-create all_items using that
all_items = [] all_items = set()
keys = m.keys() keys = m.keys()
values = m.values() values = m.values()
for k in keys: for k in keys:
all_items.append( (tuple(k), m[k[0]]) ) all_items.add( (tuple(k), m[k[0]]) )
res = list(m.items()) res = set(m.items())
assert (all_items == res), 'items() (all items): expected {0},\n\t\t\t\tbut collected {1}'.format(all_items, res) assert (all_items == res), 'items() (all items): expected {0},\n\t\t\t\tbut collected {1}'.format(all_items, res)
# now test deletion.. # now test deletion..
@ -496,23 +497,22 @@ def test_multi_key_dict():
# test iterkeys() # test iterkeys()
num_of_elements = 0 num_of_elements = 0
curr_index_in_range = 0 returned_keys = set()
for key in m.iterkeys(int): for key in m.iterkeys(int):
expected = tst_range[curr_index_in_range] returned_keys.add(key)
assert (key == expected), 'iterkeys(int): expected {0}, but received {1}'.format(expected, key)
curr_index_in_range += 1
num_of_elements += 1 num_of_elements += 1
assert(num_of_elements > 0), 'm.iteritems(int) returned generator that did not produce anything' assert(num_of_elements > 0), 'm.iteritems(int) returned generator that did not produce anything'
assert (returned_keys == set(tst_range)), 'iterkeys(int): expected {0}, but received {1}'.format(expected, key)
#test itervalues(int) #test itervalues(int)
curr_index_in_range = 0
num_of_elements = 0 num_of_elements = 0
returned_values = set()
for value in m.itervalues(int): for value in m.itervalues(int):
expected = tst_range[curr_index_in_range] returned_values.add(value)
assert (value == expected), 'itervalues(int): expected {0}, but received {1}'.format(expected, value)
curr_index_in_range += 1
num_of_elements += 1 num_of_elements += 1
assert(num_of_elements > 0), 'm.itervalues(int) returned generator that did not produce anything' assert (num_of_elements > 0), 'm.itervalues(int) returned generator that did not produce anything'
assert (returned_values == set(tst_range)), 'itervalues(int): expected {0}, but received {1}'.format(expected, value)
# test values(int) # test values(int)
res = sorted([x for x in m.values(int)]) res = sorted([x for x in m.values(int)])
@ -601,6 +601,8 @@ def test_multi_key_dict():
print ('All test passed OK!') print ('All test passed OK!')
__all__ = ["multi_key_dict"]
if __name__ == '__main__': if __name__ == '__main__':
try: try:
test_multi_key_dict() test_multi_key_dict()