Skip to content

Commit

Permalink
Fix Record.items() to support duplicate keys. See #28 for details.
Browse files Browse the repository at this point in the history
  • Loading branch information
1st1 committed Jun 30, 2017
1 parent 7aac14e commit 39b390c
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 12 deletions.
24 changes: 12 additions & 12 deletions asyncpg/protocol/record/recordobj.c
Expand Up @@ -688,7 +688,7 @@ record_iter(PyObject *seq)
typedef struct {
PyObject_HEAD
Py_ssize_t it_index;
PyObject *it_map_iter;
PyObject *it_key_iter;
ApgRecordObject *it_seq; /* Set to NULL when iterator is exhausted */
} ApgRecordItemsObject;

Expand All @@ -697,7 +697,7 @@ static void
record_items_dealloc(ApgRecordItemsObject *it)
{
PyObject_GC_UnTrack(it);
Py_CLEAR(it->it_map_iter);
Py_CLEAR(it->it_key_iter);
Py_CLEAR(it->it_seq);
PyObject_GC_Del(it);
}
Expand All @@ -706,7 +706,7 @@ record_items_dealloc(ApgRecordItemsObject *it)
static int
record_items_traverse(ApgRecordItemsObject *it, visitproc visit, void *arg)
{
Py_VISIT(it->it_map_iter);
Py_VISIT(it->it_key_iter);
Py_VISIT(it->it_seq);
return 0;
}
Expand All @@ -726,11 +726,11 @@ record_items_next(ApgRecordItemsObject *it)
return NULL;
}
assert(ApgRecord_CheckExact(seq));
assert(it->it_map_iter != NULL);
assert(it->it_key_iter != NULL);

key = PyIter_Next(it->it_map_iter);
key = PyIter_Next(it->it_key_iter);
if (key == NULL) {
/* likely it_map_iter had less items than seq has values */
/* likely it_key_iter had less items than seq has values */
goto exhausted;
}

Expand All @@ -740,7 +740,7 @@ record_items_next(ApgRecordItemsObject *it)
Py_INCREF(val);
}
else {
/* it_map_iter had more items than seq has values */
/* it_key_iter had more items than seq has values */
Py_DECREF(key);
goto exhausted;
}
Expand All @@ -757,7 +757,7 @@ record_items_next(ApgRecordItemsObject *it)
return tup;

exhausted:
Py_CLEAR(it->it_map_iter);
Py_CLEAR(it->it_key_iter);
Py_CLEAR(it->it_seq);
return NULL;
}
Expand Down Expand Up @@ -823,23 +823,23 @@ static PyObject *
record_new_items_iter(PyObject *seq)
{
ApgRecordItemsObject *it;
PyObject *map_iter;
PyObject *key_iter;

if (!ApgRecord_CheckExact(seq)) {
PyErr_BadInternalCall();
return NULL;
}

map_iter = PyObject_GetIter(((ApgRecordObject*)seq)->desc->mapping);
if (map_iter == NULL) {
key_iter = PyObject_GetIter(((ApgRecordObject*)seq)->desc->keys);
if (key_iter == NULL) {
return NULL;
}

it = PyObject_GC_New(ApgRecordItemsObject, &ApgRecordItems_Type);
if (it == NULL)
return NULL;

it->it_map_iter = map_iter;
it->it_key_iter = key_iter;
it->it_index = 0;
Py_INCREF(seq);
it->it_seq = (ApgRecordObject *)seq;
Expand Down
1 change: 1 addition & 0 deletions tests/test_record.py
Expand Up @@ -298,6 +298,7 @@ async def test_record_duplicate_colnames(self):
self.assertEqual(r['a'], 2)
self.assertEqual(r[0], 1)
self.assertEqual(repr(r), '<Record a=1 a=2>')
self.assertEqual(list(r.items()), [('a', 1), ('a', 2)])

async def test_record_isinstance(self):
"""Test that Record works with isinstance."""
Expand Down

0 comments on commit 39b390c

Please sign in to comment.